/*
*****************************************************************************
*
* Copyright (c) 2009 - 2022 Teunis van Beelen
* All rights reserved.
*
* Email: teuniz@protonmail.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the copyright holder nor the names of its
*       contributors may be used to endorse or promote products derived from
*       this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************
*/

/* compile with options "-D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE" */

#include "edflib.h"

#define EDFLIB_VERSION  (123)
#define EDFLIB_MAXFILES  (64)

#if defined(__APPLE__) || defined(__MACH__) || defined(__APPLE_CC__) || defined(__HAIKU__) || defined(__ANDROID__)

#define fopeno fopen

#else

#define fseeko fseeko64
#define ftello ftello64
#define fopeno fopen64

#endif

#ifdef _WIN32

#ifndef __MINGW32__
/* needed for visual c */
#undef fseeko
#define fseeko _fseeki64

#undef ftello
#define ftello _ftelli64

#undef fopeno
#define fopeno fopen

#endif

#endif

/* max size of annotationtext */
#define EDFLIB_WRITE_MAX_ANNOTATION_LEN  (40)

/* bytes in datarecord for EDF annotations, must be an integer multiple of three and two */
#define EDFLIB_ANNOTATION_BYTES  (114)

/* for writing only */
#define EDFLIB_MAX_ANNOTATION_CHANNELS  (64)

#define EDFLIB_ANNOT_MEMBLOCKSZ  (1000)


struct edfparamblock {
    char label[17];
    char transducer[81];
    char physdimension[9];
    double phys_min;
    double phys_max;
    int dig_min;
    int dig_max;
    char prefilter[81];
    int smp_per_record;
    char reserved[33];
    double offset;
    int buf_offset;
    double bitvalue;
    int annotation;
    long long sample_pntr;
};

struct edfhdrblock {
    FILE *file_hdl;
    char path[1024];
    int writemode;
    char version[32];
    char patient[81];
    char recording[81];
    char plus_patientcode[81];
    char plus_gender[16];
    char plus_birthdate[16];
    int plus_birthdate_day;
    int plus_birthdate_month;
    int plus_birthdate_year;
    char plus_patient_name[81];
    char plus_patient_additional[81];
    char plus_startdate[16];
    char plus_admincode[81];
    char plus_technician[81];
    char plus_equipment[81];
    char plus_recording_additional[81];
    long long l_starttime;
    int startdate_day;
    int startdate_month;
    int startdate_year;
    int starttime_second;
    int starttime_minute;
    int starttime_hour;
    char reserved[45];
    int hdrsize;
    int edfsignals;
    long long datarecords;
    int recordsize;
    int annot_ch[EDFLIB_MAXSIGNALS];
    int nr_annot_chns;
    int mapped_signals[EDFLIB_MAXSIGNALS];
    int edf;
    int edfplus;
    int bdf;
    int bdfplus;
    int discontinuous;
    int signal_write_sequence_pos;
    long long starttime_offset;
    double data_record_duration;
    long long long_data_record_duration;
    int annots_in_file;
    int annotlist_sz;
    int total_annot_bytes;
    int eq_sf;
    char *wrbuf;
    int wrbufsize;
    struct edfparamblock *edfparam;
};

static struct edf_annotationblock {
    long long onset;
    long long duration_l;
    char duration[16];
    char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1];
} *annotationslist[EDFLIB_MAXFILES];

static struct edf_write_annotationblock {
    long long onset;
    long long duration;
    char annotation[EDFLIB_WRITE_MAX_ANNOTATION_LEN + 1];
} *write_annotationslist[EDFLIB_MAXFILES];

static int edf_files_open = 0;

static struct edfhdrblock *hdrlist[EDFLIB_MAXFILES];

static struct edfhdrblock *edflib_check_edf_file(FILE *, int *);

static int edflib_is_integer_number(char *);

static int edflib_is_number(char *);

static long long edflib_get_long_duration(char *);

static int edflib_get_annotations(struct edfhdrblock *, int, int);

static int edflib_is_duration_number(char *);

static int edflib_is_onset_number(char *);

static long long edflib_get_long_time(char *);

static int edflib_write_edf_header(struct edfhdrblock *);

static void edflib_latin1_to_ascii(char *, int);

static void edflib_latin12utf8(char *, int);

static void edflib_remove_padding_trailing_spaces(char *);

static int edflib_atoi_nonlocalized(const char *);

static double edflib_atof_nonlocalized(const char *);

static int edflib_snprint_number_nonlocalized(char *, double, int);

/*
static int edflib_sprint_int_number_nonlocalized(char *, int, int, int);
*/
static int edflib_snprint_ll_number_nonlocalized(char *, long long, int, int, int);

static int edflib_fprint_int_number_nonlocalized(FILE *, int, int, int);

static int edflib_fprint_ll_number_nonlocalized(FILE *, long long, int, int);

static int edflib_write_tal(struct edfhdrblock *, FILE *);

static int edflib_strlcpy(char *, const char *, int);

static int edflib_strlcat(char *, const char *, int);

#define SAMPLES_READ   (750)

int * flutterread_physical_samples(const char *path, int page) {
    double *buf;
    struct edf_hdr_struct hdr;
    int channel = 0;
    if(edfopen_file_readonly(path, &hdr, EDFLIB_READ_ALL_ANNOTATIONS))
    {
        switch(hdr.filetype)
        {
            case EDFLIB_MALLOC_ERROR                : printf("\nmalloc error\n\n");
                break;
            case EDFLIB_NO_SUCH_FILE_OR_DIRECTORY   : printf("\ncannot open file, no such file or directory\n\n");
                break;
            case EDFLIB_FILE_CONTAINS_FORMAT_ERRORS : printf("\nthe file is not EDF(+) or BDF(+) compliant\n"
                                                             "(it contains format errors)\n\n");
                break;
            case EDFLIB_MAXFILES_REACHED            : printf("\nto many files opened\n\n");
                break;
            case EDFLIB_FILE_READ_ERROR             : printf("\na read error occurred\n\n");
                break;
            case EDFLIB_FILE_ALREADY_OPENED         : printf("\nfile has already been opened\n\n");
                break;
            default                                 : printf("\nunknown error\n\n");
                break;
        }

        return(1);
    }

    int hdl = hdr.handle;
    buf = (double *)malloc(sizeof(double[SAMPLES_READ]));
    if(buf==NULL)
    {
        printf("\nmalloc error\n");
        edfclose_file(hdl);
        return(1);
    }

    int x=page*30; /* start reading x seconds from start of file */

    edfseek(hdl, channel, (long long)((((double)x) / ((double)hdr.file_duration / (double)EDFLIB_TIME_DIMENSION)) * ((double)hdr.signalparam[channel].smp_in_file)), EDFSEEK_SET);

    int n = edfread_physical_samples(hdl, channel, SAMPLES_READ, buf);
    printf("len=%d", n);

    if(n==(-1))
    {
        printf("\nerror: edf_read_physical_samples()\n");
        edfclose_file(hdl);
        free(buf);
        return(1);
    }

    printf("\nread %i samples, started at %i seconds from start of file:\n\n", n, x);

    int * bufInt = (int *)malloc(sizeof(int[n]));

    for(int i=0; i<n; i++)
    {
        bufInt[i] = (int)buf[i];
        printf(" %d  ", bufInt[i]);
    }


    edfclose_file(hdl);
    return bufInt;
}

int flutter_total_page(const char *path) {
    double *buf;
    struct edf_hdr_struct hdr;
    int channel = 0;

    edfopen_file_readonly(path, &hdr, EDFLIB_READ_ALL_ANNOTATIONS);

    int hdl = hdr.handle;
    int page = hdr.file_duration/30/10000000;
    edfclose_file(hdl);
    return page;
}

int edflib_is_file_used(const char *path) {
    int i;

    for (i = 0; i < EDFLIB_MAXFILES; i++) {
        if (hdrlist[i] != NULL) {
            if (!(strcmp(path, hdrlist[i]->path))) return 1;
        }
    }

    return 0;
}


int edflib_get_number_of_open_files() {
    return edf_files_open;
}


int edflib_get_handle(int file_number) {
    int i, file_count = 0;

    for (i = 0; i < EDFLIB_MAXFILES; i++) {
        if (hdrlist[i] != NULL) {
            if (file_count++ == file_number) return i;
        }
    }

    return -1;
}


int
edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int read_annotations_mode) {
    int i, j,
            channel,
            edf_error;

    FILE *file;

    struct edfhdrblock *hdr;

    union {
        char four[4];
        int one;
    } byte_order_test_var;

    memset(edfhdr, 0, sizeof(struct edf_hdr_struct));

    /* avoid surprises! */
    if ((sizeof(char) != 1) ||
        (sizeof(short) != 2) ||
        (sizeof(int) != 4) ||
        (sizeof(long long) != 8) ||
        (sizeof(float) != 4) ||
        (sizeof(double) != 8)) {
        edfhdr->filetype = EDFLIB_ARCH_ERROR;

        return -1;
    }

    /* check endianness! */
    byte_order_test_var.one = 0x03020100;
    if ((byte_order_test_var.four[0] != 0) ||
        (byte_order_test_var.four[1] != 1) ||
        (byte_order_test_var.four[2] != 2) ||
        (byte_order_test_var.four[3] != 3)) {
        edfhdr->filetype = EDFLIB_ARCH_ERROR;

        return -1;
    }

    if ((read_annotations_mode < 0) || (read_annotations_mode > 2)) {
        edfhdr->filetype = EDFLIB_INVALID_READ_ANNOTS_VALUE;

        return -1;
    }

    if (edf_files_open >= EDFLIB_MAXFILES) {
        edfhdr->filetype = EDFLIB_MAXFILES_REACHED;

        return -1;
    }

    for (i = 0; i < EDFLIB_MAXFILES; i++) {
        if (hdrlist[i] != NULL) {
            if (!(strcmp(path, hdrlist[i]->path))) {
                edfhdr->filetype = EDFLIB_FILE_ALREADY_OPENED;

                return -1;
            }
        }
    }

    file = fopeno(path, "rb");
    if (file == NULL) {
        edfhdr->filetype = EDFLIB_NO_SUCH_FILE_OR_DIRECTORY;

        return -1;
    }

    hdr = edflib_check_edf_file(file, &edf_error);
    if (hdr == NULL) {
        edfhdr->filetype = edf_error;

        fclose(file);

        return -1;
    }

    if (hdr->discontinuous) {
        edfhdr->filetype = EDFLIB_FILE_IS_DISCONTINUOUS;

        free(hdr->edfparam);
        free(hdr);

        fclose(file);

        return -1;
    }

    for (i = 0; i < EDFLIB_MAXFILES; i++) {
        if (hdrlist[i] == NULL) {
            hdrlist[i] = hdr;

            edfhdr->handle = i;

            break;
        }
    }

    if ((hdr->edf) && (!(hdr->edfplus))) {
        edfhdr->filetype = EDFLIB_FILETYPE_EDF;
    }

    if (hdr->edfplus) {
        edfhdr->filetype = EDFLIB_FILETYPE_EDFPLUS;
    }

    if ((hdr->bdf) && (!(hdr->bdfplus))) {
        edfhdr->filetype = EDFLIB_FILETYPE_BDF;
    }

    if (hdr->bdfplus) {
        edfhdr->filetype = EDFLIB_FILETYPE_BDFPLUS;
    }

    edfhdr->edfsignals = hdr->edfsignals - hdr->nr_annot_chns;
    edfhdr->file_duration = hdr->long_data_record_duration * hdr->datarecords;
    edfhdr->startdate_day = hdr->startdate_day;
    edfhdr->startdate_month = hdr->startdate_month;
    edfhdr->startdate_year = hdr->startdate_year;
    edfhdr->starttime_hour = hdr->starttime_hour;
    edfhdr->starttime_second = hdr->starttime_second;
    edfhdr->starttime_minute = hdr->starttime_minute;
    edfhdr->starttime_subsecond = hdr->starttime_offset;
    edfhdr->datarecords_in_file = hdr->datarecords;
    edfhdr->datarecord_duration = hdr->long_data_record_duration;

    annotationslist[edfhdr->handle] = NULL;

    hdr->annotlist_sz = 0;

    hdr->annots_in_file = 0;

    edfhdr->annotations_in_file = 0LL;

    if ((!(hdr->edfplus)) && (!(hdr->bdfplus))) {
        edflib_strlcpy(edfhdr->patient, hdr->patient, 81);
        edflib_strlcpy(edfhdr->recording, hdr->recording, 81);
    } else {
        edflib_strlcpy(edfhdr->patientcode, hdr->plus_patientcode, 81);
        edflib_strlcpy(edfhdr->gender, hdr->plus_gender, 16);
        edflib_strlcpy(edfhdr->birthdate, hdr->plus_birthdate, 16);
        edfhdr->birthdate_day = hdr->plus_birthdate_day;
        edfhdr->birthdate_month = hdr->plus_birthdate_month;
        edfhdr->birthdate_year = hdr->plus_birthdate_year;
        edflib_strlcpy(edfhdr->patient_name, hdr->plus_patient_name, 81);
        edflib_strlcpy(edfhdr->patient_additional, hdr->plus_patient_additional, 81);
        edflib_strlcpy(edfhdr->admincode, hdr->plus_admincode, 81);
        edflib_strlcpy(edfhdr->technician, hdr->plus_technician, 81);
        edflib_strlcpy(edfhdr->equipment, hdr->plus_equipment, 81);
        edflib_strlcpy(edfhdr->recording_additional, hdr->plus_recording_additional, 81);

        if (edflib_get_annotations(hdr, edfhdr->handle, read_annotations_mode)) {
            edfhdr->filetype = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;

            fclose(file);

            free(hdr->edfparam);
            hdr->edfparam = NULL;
            free(hdr);
            hdr = NULL;
            hdrlist[edfhdr->handle] = NULL;
            free(annotationslist[edfhdr->handle]);
            annotationslist[edfhdr->handle] = NULL;

            return -1;
        }

        edfhdr->starttime_subsecond = hdr->starttime_offset;

        edfhdr->annotations_in_file = hdr->annots_in_file;
    }

    edflib_strlcpy(hdr->path, path, 1024);

    edf_files_open++;

    j = 0;

    for (i = 0; i < hdr->edfsignals; i++) {
        if (!(hdr->edfparam[i].annotation)) {
            hdr->mapped_signals[j++] = i;
        }
    }

    for (i = 0; i < edfhdr->edfsignals; i++) {
        channel = hdr->mapped_signals[i];

        edflib_strlcpy(edfhdr->signalparam[i].label, hdr->edfparam[channel].label, 17);
        edflib_strlcpy(edfhdr->signalparam[i].transducer, hdr->edfparam[channel].transducer, 81);
        edflib_strlcpy(edfhdr->signalparam[i].physdimension, hdr->edfparam[channel].physdimension,
                       9);
        edflib_strlcpy(edfhdr->signalparam[i].prefilter, hdr->edfparam[channel].prefilter, 81);
        edfhdr->signalparam[i].smp_in_file =
                hdr->edfparam[channel].smp_per_record * hdr->datarecords;
        edfhdr->signalparam[i].phys_max = hdr->edfparam[channel].phys_max;
        edfhdr->signalparam[i].phys_min = hdr->edfparam[channel].phys_min;
        edfhdr->signalparam[i].dig_max = hdr->edfparam[channel].dig_max;
        edfhdr->signalparam[i].dig_min = hdr->edfparam[channel].dig_min;
        edfhdr->signalparam[i].smp_in_datarecord = hdr->edfparam[channel].smp_per_record;
    }

    return 0;
}

//同步文件，以免没有结束造成文件损坏
int synchronize(int handle) {
    struct edf_write_annotationblock *annot2;

    int i, j, k, n, p, err,
            datrecsize,
            nmemb;

    long long offset,
            datarecords;

    char str[EDFLIB_ANNOTATION_BYTES * 2];

    struct edfhdrblock *hdr;


    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    hdr = hdrlist[handle];

    if (hdr->writemode) {
        if (hdr->datarecords == 0LL) {
            err = edflib_write_edf_header(hdr);
            if (err) {
                fclose(hdr->file_hdl);

                free(hdr->edfparam);

                free(hdr->wrbuf);

                free(hdr);

                hdrlist[handle] = NULL;

                free(write_annotationslist[handle]);

                write_annotationslist[handle] = NULL;

                edf_files_open--;

                return err;
            }

            for (k = 0; k < hdr->annots_in_file; k++) {
                annot2 = write_annotationslist[handle] + k;

                p = edflib_fprint_ll_number_nonlocalized(hdr->file_hdl, (hdr->datarecords *
                                                                         hdr->long_data_record_duration +
                                                                         hdr->starttime_offset) /
                                                                        EDFLIB_TIME_DIMENSION, 0,
                                                         1);

                if ((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) ||
                    (hdr->starttime_offset)) {
                    fputc('.', hdr->file_hdl);
                    p++;
                    p += edflib_fprint_ll_number_nonlocalized(hdr->file_hdl, (hdr->datarecords *
                                                                              hdr->long_data_record_duration +
                                                                              hdr->starttime_offset) %
                                                                             EDFLIB_TIME_DIMENSION,
                                                              7, 0);
                }
                fputc(20, hdr->file_hdl);
                fputc(20, hdr->file_hdl);
                p += 2;
                for (; p < hdr->total_annot_bytes; p++) {
                    fputc(0, hdr->file_hdl);
                }

                hdr->datarecords++;
            }
        }

        if (hdr->datarecords < 100000000LL) {
            fseeko(hdr->file_hdl, 236LL, SEEK_SET);
            p = edflib_fprint_int_number_nonlocalized(hdr->file_hdl, (int) (hdr->datarecords), 0,
                                                      0);
            if (p < 2) {
                fputc(' ', hdr->file_hdl);
            }
        }

        datarecords = 0LL;

        offset = (long long) ((hdr->edfsignals + hdr->nr_annot_chns + 1) * 256);

        datrecsize = hdr->total_annot_bytes;

        for (i = 0; i < hdr->edfsignals; i++) {
            if (hdr->edf) {
                offset += (long long) (hdr->edfparam[i].smp_per_record * 2);

                datrecsize += (hdr->edfparam[i].smp_per_record * 2);
            } else {
                offset += (long long) (hdr->edfparam[i].smp_per_record * 3);

                datrecsize += (hdr->edfparam[i].smp_per_record * 3);
            }
        }

        j = 0;

        for (k = 0; k < hdr->annots_in_file; k++) {
            annot2 = write_annotationslist[handle] + k;

            annot2->onset += hdr->starttime_offset / 1000LL;

            p = 0;

            if (j == 0)  // first annotation signal
            {
                if (fseeko(hdr->file_hdl, offset, SEEK_SET)) {
                    break;
                }

                p += edflib_snprint_ll_number_nonlocalized(str, (datarecords *
                                                                 hdr->long_data_record_duration +
                                                                 hdr->starttime_offset) /
                                                                EDFLIB_TIME_DIMENSION, 0, 1,
                                                           EDFLIB_ANNOTATION_BYTES * 2);

                if ((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) ||
                    (hdr->starttime_offset)) {
                    str[p++] = '.';
                    n = edflib_snprint_ll_number_nonlocalized(str + p, (datarecords *
                                                                        hdr->long_data_record_duration +
                                                                        hdr->starttime_offset) %
                                                                       EDFLIB_TIME_DIMENSION, 7, 0,
                                                              (EDFLIB_ANNOTATION_BYTES * 2) - p);
                    p += n;
                }
                str[p++] = 20;
                str[p++] = 20;
                str[p++] = 0;
            }

            n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset / 10000LL, 0, 1,
                                                      (EDFLIB_ANNOTATION_BYTES * 2) - p);
            p += n;
            if (annot2->onset % 10000LL) {
                str[p++] = '.';
                n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset % 10000LL, 4, 0,
                                                          (EDFLIB_ANNOTATION_BYTES * 2) - p);
                p += n;
            }
            if (annot2->duration >= 0LL) {
                str[p++] = 21;
                n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration / 10000LL, 0, 0,
                                                          (EDFLIB_ANNOTATION_BYTES * 2) - p);
                p += n;
                if (annot2->duration % 10000LL) {
                    str[p++] = '.';
                    n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration % 10000LL,
                                                              4, 0,
                                                              (EDFLIB_ANNOTATION_BYTES * 2) - p);
                    p += n;
                }
            }
            str[p++] = 20;
            for (i = 0; i < EDFLIB_WRITE_MAX_ANNOTATION_LEN; i++) {
                if (annot2->annotation[i] == 0) {
                    break;
                }

                str[p++] = annot2->annotation[i];
            }
            str[p++] = 20;

            for (; p < EDFLIB_ANNOTATION_BYTES; p++) {
                str[p] = 0;
            }

            nmemb = fwrite(str, EDFLIB_ANNOTATION_BYTES, 1, hdr->file_hdl);

            if (nmemb != 1) {
                break;
            }

            j++;

            if (j >= hdr->nr_annot_chns) {
                j = 0;

                offset += datrecsize;

                datarecords++;

                if (datarecords >= hdr->datarecords) {
                    break;
                }
            }
        }
        //把文件指针移到文件末尾，以便下次新数据写入
        fseeko(hdr->file_hdl, 0, SEEK_END);
    }
    return 0;

}

int edfclose_file(int handle) {
    struct edf_write_annotationblock *annot2;

    int i, j, k, n, p, err,
            datrecsize,
            nmemb;

    long long offset,
            datarecords;

    char str[EDFLIB_ANNOTATION_BYTES * 2];

    struct edfhdrblock *hdr;


    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    hdr = hdrlist[handle];

    if (hdr->writemode) {
        if (hdr->datarecords == 0LL) {
            err = edflib_write_edf_header(hdr);
            if (err) {
                fclose(hdr->file_hdl);

                free(hdr->edfparam);

                free(hdr->wrbuf);

                free(hdr);

                hdrlist[handle] = NULL;

                free(write_annotationslist[handle]);

                write_annotationslist[handle] = NULL;

                edf_files_open--;

                return err;
            }

            for (k = 0; k < hdr->annots_in_file; k++) {
                annot2 = write_annotationslist[handle] + k;

                p = edflib_fprint_ll_number_nonlocalized(hdr->file_hdl, (hdr->datarecords *
                                                                         hdr->long_data_record_duration +
                                                                         hdr->starttime_offset) /
                                                                        EDFLIB_TIME_DIMENSION, 0,
                                                         1);

                if ((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) ||
                    (hdr->starttime_offset)) {
                    fputc('.', hdr->file_hdl);
                    p++;
                    p += edflib_fprint_ll_number_nonlocalized(hdr->file_hdl, (hdr->datarecords *
                                                                              hdr->long_data_record_duration +
                                                                              hdr->starttime_offset) %
                                                                             EDFLIB_TIME_DIMENSION,
                                                              7, 0);
                }
                fputc(20, hdr->file_hdl);
                fputc(20, hdr->file_hdl);
                p += 2;
                for (; p < hdr->total_annot_bytes; p++) {
                    fputc(0, hdr->file_hdl);
                }

                hdr->datarecords++;
            }
        }

        if (hdr->datarecords < 100000000LL) {
            fseeko(hdr->file_hdl, 236LL, SEEK_SET);
            p = edflib_fprint_int_number_nonlocalized(hdr->file_hdl, (int) (hdr->datarecords), 0,
                                                      0);
            if (p < 2) {
                fputc(' ', hdr->file_hdl);
            }
        }

        datarecords = 0LL;

        offset = (long long) ((hdr->edfsignals + hdr->nr_annot_chns + 1) * 256);

        datrecsize = hdr->total_annot_bytes;

        for (i = 0; i < hdr->edfsignals; i++) {
            if (hdr->edf) {
                offset += (long long) (hdr->edfparam[i].smp_per_record * 2);

                datrecsize += (hdr->edfparam[i].smp_per_record * 2);
            } else {
                offset += (long long) (hdr->edfparam[i].smp_per_record * 3);

                datrecsize += (hdr->edfparam[i].smp_per_record * 3);
            }
        }

        j = 0;

        for (k = 0; k < hdr->annots_in_file; k++) {
            annot2 = write_annotationslist[handle] + k;

            annot2->onset += hdr->starttime_offset / 1000LL;

            p = 0;

            if (j == 0)  // first annotation signal
            {
                if (fseeko(hdr->file_hdl, offset, SEEK_SET)) {
                    break;
                }

                p += edflib_snprint_ll_number_nonlocalized(str, (datarecords *
                                                                 hdr->long_data_record_duration +
                                                                 hdr->starttime_offset) /
                                                                EDFLIB_TIME_DIMENSION, 0, 1,
                                                           EDFLIB_ANNOTATION_BYTES * 2);

                if ((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) ||
                    (hdr->starttime_offset)) {
                    str[p++] = '.';
                    n = edflib_snprint_ll_number_nonlocalized(str + p, (datarecords *
                                                                        hdr->long_data_record_duration +
                                                                        hdr->starttime_offset) %
                                                                       EDFLIB_TIME_DIMENSION, 7, 0,
                                                              (EDFLIB_ANNOTATION_BYTES * 2) - p);
                    p += n;
                }
                str[p++] = 20;
                str[p++] = 20;
                str[p++] = 0;
            }

            n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset / 10000LL, 0, 1,
                                                      (EDFLIB_ANNOTATION_BYTES * 2) - p);
            p += n;
            if (annot2->onset % 10000LL) {
                str[p++] = '.';
                n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->onset % 10000LL, 4, 0,
                                                          (EDFLIB_ANNOTATION_BYTES * 2) - p);
                p += n;
            }
            if (annot2->duration >= 0LL) {
                str[p++] = 21;
                n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration / 10000LL, 0, 0,
                                                          (EDFLIB_ANNOTATION_BYTES * 2) - p);
                p += n;
                if (annot2->duration % 10000LL) {
                    str[p++] = '.';
                    n = edflib_snprint_ll_number_nonlocalized(str + p, annot2->duration % 10000LL,
                                                              4, 0,
                                                              (EDFLIB_ANNOTATION_BYTES * 2) - p);
                    p += n;
                }
            }
            str[p++] = 20;
            for (i = 0; i < EDFLIB_WRITE_MAX_ANNOTATION_LEN; i++) {
                if (annot2->annotation[i] == 0) {
                    break;
                }

                str[p++] = annot2->annotation[i];
            }
            str[p++] = 20;

            for (; p < EDFLIB_ANNOTATION_BYTES; p++) {
                str[p] = 0;
            }

            nmemb = fwrite(str, EDFLIB_ANNOTATION_BYTES, 1, hdr->file_hdl);

            if (nmemb != 1) {
                break;
            }

            j++;

            if (j >= hdr->nr_annot_chns) {
                j = 0;

                offset += datrecsize;

                datarecords++;

                if (datarecords >= hdr->datarecords) {
                    break;
                }
            }
        }

        free(write_annotationslist[handle]);
    } else {
        free(annotationslist[handle]);
    }

    fclose(hdr->file_hdl);

    free(hdr->edfparam);

    free(hdr->wrbuf);

    free(hdr);

    hdrlist[handle] = NULL;

    edf_files_open--;

    return 0;
}


long long edfseek(int handle, int edfsignal, long long offset, int whence) {
    long long smp_in_file;

    int channel;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (edfsignal < 0) return -1;

    if (hdrlist[handle]->writemode) return -1;

    if (edfsignal >= (hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1;

    channel = hdrlist[handle]->mapped_signals[edfsignal];

    smp_in_file = hdrlist[handle]->edfparam[channel].smp_per_record * hdrlist[handle]->datarecords;

    if (whence == EDFSEEK_SET) {
        hdrlist[handle]->edfparam[channel].sample_pntr = offset;
    }

    if (whence == EDFSEEK_CUR) {
        hdrlist[handle]->edfparam[channel].sample_pntr += offset;
    }

    if (whence == EDFSEEK_END) {
        hdrlist[handle]->edfparam[channel].sample_pntr =
                (hdrlist[handle]->edfparam[channel].smp_per_record * hdrlist[handle]->datarecords) +
                offset;
    }

    if (hdrlist[handle]->edfparam[channel].sample_pntr > smp_in_file) {
        hdrlist[handle]->edfparam[channel].sample_pntr = smp_in_file;
    }

    if (hdrlist[handle]->edfparam[channel].sample_pntr < 0LL) {
        hdrlist[handle]->edfparam[channel].sample_pntr = 0LL;
    }

    return hdrlist[handle]->edfparam[channel].sample_pntr;
}


long long edftell(int handle, int edfsignal) {
    int channel;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (edfsignal < 0) return -1;

    if (hdrlist[handle]->writemode) return -1;

    if (edfsignal >= (hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1;

    channel = hdrlist[handle]->mapped_signals[edfsignal];

    return hdrlist[handle]->edfparam[channel].sample_pntr;
}


void edfrewind(int handle, int edfsignal) {
    int channel;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return;

    if (hdrlist[handle] == NULL) return;

    if (edfsignal < 0) return;

    if (hdrlist[handle]->writemode) return;

    if (edfsignal >= (hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return;

    channel = hdrlist[handle]->mapped_signals[edfsignal];

    hdrlist[handle]->edfparam[channel].sample_pntr = 0LL;
}


int edfread_physical_samples(int handle, int edfsignal, int n, double *buf) {
    int bytes_per_smpl = 2,
            tmp,
            i,
            channel;

    double phys_bitvalue,
            phys_offset;

    long long smp_in_file,
            offset,
            sample_pntr,
            smp_per_record,
            jump;

    struct edfhdrblock *hdr;

    union {
        unsigned int one;
        signed int one_signed;
        unsigned short two[2];
        signed short two_signed[2];
        unsigned char four[4];
    } var;

    FILE *file;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (edfsignal < 0) return -1;

    if (hdrlist[handle]->writemode) return -1;

    if (edfsignal >= (hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1;

    channel = hdrlist[handle]->mapped_signals[edfsignal];

    if (n < 0LL) return -1;

    if (n == 0LL) return 0LL;

    hdr = hdrlist[handle];

    if (hdr->edf) {
        bytes_per_smpl = 2;
    }

    if (hdr->bdf) {
        bytes_per_smpl = 3;
    }

    smp_in_file = hdr->edfparam[channel].smp_per_record * hdr->datarecords;

    if ((hdr->edfparam[channel].sample_pntr + n) > smp_in_file) {
        n = smp_in_file - hdr->edfparam[channel].sample_pntr;

        if (n == 0) return 0LL;

        if (n < 0) return -1;
    }

    file = hdr->file_hdl;

    offset = hdr->hdrsize;
    offset += (hdr->edfparam[channel].sample_pntr / hdr->edfparam[channel].smp_per_record) *
              hdr->recordsize;
    offset += hdr->edfparam[channel].buf_offset;
    offset += ((hdr->edfparam[channel].sample_pntr % hdr->edfparam[channel].smp_per_record) *
               bytes_per_smpl);

    fseeko(file, offset, SEEK_SET);

    sample_pntr = hdr->edfparam[channel].sample_pntr;

    smp_per_record = hdr->edfparam[channel].smp_per_record;

    jump = hdr->recordsize - (smp_per_record * bytes_per_smpl);

    phys_bitvalue = hdr->edfparam[channel].bitvalue;

    phys_offset = hdr->edfparam[channel].offset;

    if (hdr->edf) {
        for (i = 0; i < n; i++) {
            if (!(sample_pntr % smp_per_record)) {
                if (i) {
                    fseeko(file, jump, SEEK_CUR);
                }
            }

            var.four[0] = fgetc(file);
            tmp = fgetc(file);
            if (tmp == EOF) {
                return -1;
            }
            var.four[1] = tmp;

            if (var.two_signed[0] > hdr->edfparam[channel].dig_max) {
                var.two_signed[0] = hdr->edfparam[channel].dig_max;
            } else if (var.two_signed[0] < hdr->edfparam[channel].dig_min) {
                var.two_signed[0] = hdr->edfparam[channel].dig_min;
            }

            buf[i] = phys_bitvalue * (phys_offset + (double) var.two_signed[0]);

            sample_pntr++;
        }
    }

    if (hdr->bdf) {
        for (i = 0; i < n; i++) {
            if (!(sample_pntr % smp_per_record)) {
                if (i) {
                    fseeko(file, jump, SEEK_CUR);
                }
            }

            var.four[0] = fgetc(file);
            var.four[1] = fgetc(file);
            tmp = fgetc(file);
            if (tmp == EOF) return -1;
            var.four[2] = tmp;

            if (var.four[2] & 0x80) {
                var.four[3] = 0xff;
            } else {
                var.four[3] = 0x00;
            }

            if (var.one_signed > hdr->edfparam[channel].dig_max) {
                var.one_signed = hdr->edfparam[channel].dig_max;
            } else if (var.one_signed < hdr->edfparam[channel].dig_min) {
                var.one_signed = hdr->edfparam[channel].dig_min;
            }

            buf[i] = phys_bitvalue * (phys_offset + (double) var.one_signed);

            sample_pntr++;
        }
    }

    hdr->edfparam[channel].sample_pntr = sample_pntr;

    return n;
}


int edfread_digital_samples(int handle, int edfsignal, int n, int *buf) {
    int bytes_per_smpl = 2,
            tmp,
            i,
            channel;

    long long smp_in_file,
            offset,
            sample_pntr,
            smp_per_record,
            jump;

    struct edfhdrblock *hdr;

    union {
        unsigned int one;
        signed int one_signed;
        unsigned short two[2];
        signed short two_signed[2];
        unsigned char four[4];
    } var;

    FILE *file;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (edfsignal < 0) return -1;

    if (hdrlist[handle]->writemode) return -1;

    if (edfsignal >= (hdrlist[handle]->edfsignals - hdrlist[handle]->nr_annot_chns)) return -1;

    channel = hdrlist[handle]->mapped_signals[edfsignal];

    if (n < 0LL) return -1;

    if (n == 0LL) return 0LL;

    hdr = hdrlist[handle];

    if (hdr->edf) {
        bytes_per_smpl = 2;
    }

    if (hdr->bdf) {
        bytes_per_smpl = 3;
    }

    smp_in_file = hdr->edfparam[channel].smp_per_record * hdr->datarecords;

    if ((hdr->edfparam[channel].sample_pntr + n) > smp_in_file) {
        n = smp_in_file - hdr->edfparam[channel].sample_pntr;

        if (n == 0) {
            return 0LL;
        }

        if (n < 0) {
            return -1;
        }
    }

    file = hdr->file_hdl;

    offset = hdr->hdrsize;
    offset += (hdr->edfparam[channel].sample_pntr / hdr->edfparam[channel].smp_per_record) *
              hdr->recordsize;
    offset += hdr->edfparam[channel].buf_offset;
    offset += ((hdr->edfparam[channel].sample_pntr % hdr->edfparam[channel].smp_per_record) *
               bytes_per_smpl);

    fseeko(file, offset, SEEK_SET);

    sample_pntr = hdr->edfparam[channel].sample_pntr;

    smp_per_record = hdr->edfparam[channel].smp_per_record;

    jump = hdr->recordsize - (smp_per_record * bytes_per_smpl);

    if (hdr->edf) {
        for (i = 0; i < n; i++) {
            if (!(sample_pntr % smp_per_record)) {
                if (i) {
                    fseeko(file, jump, SEEK_CUR);
                }
            }

            var.four[0] = fgetc(file);
            tmp = fgetc(file);
            if (tmp == EOF) return -1;
            var.four[1] = tmp;

            if (var.two_signed[0] > hdr->edfparam[channel].dig_max) {
                var.two_signed[0] = hdr->edfparam[channel].dig_max;
            } else if (var.two_signed[0] < hdr->edfparam[channel].dig_min) {
                var.two_signed[0] = hdr->edfparam[channel].dig_min;
            }

            buf[i] = var.two_signed[0];

            sample_pntr++;
        }
    }

    if (hdr->bdf) {
        for (i = 0; i < n; i++) {
            if (!(sample_pntr % smp_per_record)) {
                if (i) {
                    fseeko(file, jump, SEEK_CUR);
                }
            }

            var.four[0] = fgetc(file);
            var.four[1] = fgetc(file);
            tmp = fgetc(file);
            if (tmp == EOF) return -1;
            var.four[2] = tmp;

            if (var.four[2] & 0x80) {
                var.four[3] = 0xff;
            } else {
                var.four[3] = 0x00;
            }

            if (var.one_signed > hdr->edfparam[channel].dig_max) {
                var.one_signed = hdr->edfparam[channel].dig_max;
            } else if (var.one_signed < hdr->edfparam[channel].dig_min) {
                var.one_signed = hdr->edfparam[channel].dig_min;
            }

            buf[i] = var.one_signed;

            sample_pntr++;
        }
    }

    hdr->edfparam[channel].sample_pntr = sample_pntr;

    return n;
}


int edf_get_annotation(int handle, int n, struct edf_annotation_struct *annot) {
    memset(annot, 0, sizeof(struct edf_annotation_struct));

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (hdrlist[handle]->writemode) return -1;

    if (n < 0) return -1;

    if (n >= hdrlist[handle]->annots_in_file) return -1;

    annot->onset = (annotationslist[handle] + n)->onset;
    annot->duration_l = (annotationslist[handle] + n)->duration_l;
    edflib_strlcpy(annot->duration, (annotationslist[handle] + n)->duration, 16);
    edflib_strlcpy(annot->annotation, (annotationslist[handle] + n)->annotation,
                   EDFLIB_MAX_ANNOTATION_LEN + 1);

    return 0;
}


static struct edfhdrblock *edflib_check_edf_file(FILE *inputfile, int *edf_error) {
    int i, j, p, r = 0, n,
            dotposition,
            error;

    char *edf_hdr,
            scratchpad[128],
            scratchpad2[64];

    struct edfhdrblock *edfhdr;

/***************** check header ******************************/

    edf_hdr = (char *) calloc(1, 256);
    if (edf_hdr == NULL) {
        *edf_error = EDFLIB_MALLOC_ERROR;
        return NULL;
    }

    edfhdr = (struct edfhdrblock *) calloc(1, sizeof(struct edfhdrblock));
    if (edfhdr == NULL) {
        free(edf_hdr);
        *edf_error = EDFLIB_MALLOC_ERROR;
        return NULL;
    }

    rewind(inputfile);
    if (fread(edf_hdr, 256, 1, inputfile) != 1) {
        *edf_error = EDFLIB_FILE_READ_ERROR;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

/**************************** VERSION ***************************************/

    strncpy(scratchpad, edf_hdr, 8);
    scratchpad[8] = 0;

    if (((signed char *) scratchpad)[0] == -1)   /* BDF-file */
    {
        for (i = 1; i < 8; i++) {
            if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr);
                return NULL;
            }
        }

        if (strcmp(scratchpad + 1, "BIOSEMI")) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }

        edfhdr->bdf = 1;
    } else    /* EDF-file */
    {
        for (i = 0; i < 8; i++) {
            if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr);
                return NULL;
            }
        }

        if (strcmp(scratchpad, "0       ")) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }

        edfhdr->edf = 1;
    }

    strncpy(edfhdr->version, edf_hdr, 8);
    edfhdr->version[8] = 0;
    if (edfhdr->bdf) edfhdr->version[0] = '.';

/********************* PATIENTNAME *********************************************/

    strncpy(scratchpad, edf_hdr + 8, 80);
    scratchpad[80] = 0;
    for (i = 0; i < 80; i++) {
        if ((((unsigned char *) scratchpad)[i] < 32) || (((unsigned char *) scratchpad)[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    strncpy(edfhdr->patient, edf_hdr + 8, 80);
    edfhdr->patient[80] = 0;

/********************* RECORDING *********************************************/

    strncpy(scratchpad, edf_hdr + 88, 80);
    scratchpad[80] = 0;
    for (i = 0; i < 80; i++) {
        if ((((unsigned char *) scratchpad)[i] < 32) || (((unsigned char *) scratchpad)[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    strncpy(edfhdr->recording, edf_hdr + 88, 80);
    edfhdr->recording[80] = 0;

/********************* STARTDATE *********************************************/

    strncpy(scratchpad, edf_hdr + 168, 8);
    scratchpad[8] = 0;
    for (i = 0; i < 8; i++) {
        if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    error = 0;

    if ((edf_hdr[170] != '.') || (edf_hdr[173] != '.')) error = 1;
    if ((edf_hdr[168] < 48) || (edf_hdr[168] > 57)) error = 1;
    if ((edf_hdr[169] < 48) || (edf_hdr[169] > 57)) error = 1;
    if ((edf_hdr[171] < 48) || (edf_hdr[171] > 57)) error = 1;
    if ((edf_hdr[172] < 48) || (edf_hdr[172] > 57)) error = 1;
    if ((edf_hdr[174] < 48) || (edf_hdr[174] > 57)) error = 1;
    if ((edf_hdr[175] < 48) || (edf_hdr[175] > 57)) error = 1;
    strncpy(scratchpad, edf_hdr + 168, 8);

    if (error) {
        scratchpad[8] = 0;
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    scratchpad[2] = 0;
    scratchpad[5] = 0;
    scratchpad[8] = 0;

    if ((edflib_atoi_nonlocalized(scratchpad) < 1) || (edflib_atoi_nonlocalized(scratchpad) > 31)) {
        strncpy(scratchpad, edf_hdr + 168, 8);
        scratchpad[8] = 0;
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    if ((edflib_atoi_nonlocalized(scratchpad + 3) < 1) ||
        (edflib_atoi_nonlocalized(scratchpad + 3) > 12)) {
        strncpy(scratchpad, edf_hdr + 168, 8);
        scratchpad[8] = 0;
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    edfhdr->startdate_day = edflib_atoi_nonlocalized(scratchpad);
    edfhdr->startdate_month = edflib_atoi_nonlocalized(scratchpad + 3);
    edfhdr->startdate_year = edflib_atoi_nonlocalized(scratchpad + 6);
    if (edfhdr->startdate_year > 84) {
        edfhdr->startdate_year += 1900;
    } else {
        edfhdr->startdate_year += 2000;
    }

/********************* STARTTIME *********************************************/

    strncpy(scratchpad, edf_hdr + 176, 8);
    scratchpad[8] = 0;
    for (i = 0; i < 8; i++) {
        if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    error = 0;

    if ((edf_hdr[178] != '.') || (edf_hdr[181] != '.')) error = 1;
    if ((edf_hdr[176] < 48) || (edf_hdr[176] > 57)) error = 1;
    if ((edf_hdr[177] < 48) || (edf_hdr[177] > 57)) error = 1;
    if ((edf_hdr[179] < 48) || (edf_hdr[179] > 57)) error = 1;
    if ((edf_hdr[180] < 48) || (edf_hdr[180] > 57)) error = 1;
    if ((edf_hdr[182] < 48) || (edf_hdr[182] > 57)) error = 1;
    if ((edf_hdr[183] < 48) || (edf_hdr[183] > 57)) error = 1;

    strncpy(scratchpad, edf_hdr + 176, 8);

    if (error) {
        strncpy(scratchpad, edf_hdr + 176, 8);
        scratchpad[8] = 0;
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    scratchpad[2] = 0;
    scratchpad[5] = 0;
    scratchpad[8] = 0;

    if (edflib_atoi_nonlocalized(scratchpad) > 23) {
        strncpy(scratchpad, edf_hdr + 176, 8);
        scratchpad[8] = 0;
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    if (edflib_atoi_nonlocalized(scratchpad + 3) > 59) {
        strncpy(scratchpad, edf_hdr + 176, 8);
        scratchpad[8] = 0;
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    if (edflib_atoi_nonlocalized(scratchpad + 6) > 59) {
        strncpy(scratchpad, edf_hdr + 176, 8);
        scratchpad[8] = 0;
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    edfhdr->starttime_hour = edflib_atoi_nonlocalized(scratchpad);
    edfhdr->starttime_minute = edflib_atoi_nonlocalized(scratchpad + 3);
    edfhdr->starttime_second = edflib_atoi_nonlocalized(scratchpad + 6);

    edfhdr->l_starttime = 3600 * edflib_atoi_nonlocalized(scratchpad);
    edfhdr->l_starttime += 60 * edflib_atoi_nonlocalized(scratchpad + 3);
    edfhdr->l_starttime += edflib_atoi_nonlocalized(scratchpad + 6);

    edfhdr->l_starttime *= EDFLIB_TIME_DIMENSION;

/***************** NUMBER OF SIGNALS IN HEADER *******************************/

    strncpy(scratchpad, edf_hdr + 252, 4);
    scratchpad[4] = 0;
    for (i = 0; i < 4; i++) {
        if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    if (edflib_is_integer_number(scratchpad)) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }
    edfhdr->edfsignals = edflib_atoi_nonlocalized(scratchpad);
    if (edfhdr->edfsignals < 1) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    if (edfhdr->edfsignals > EDFLIB_MAXSIGNALS) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

/***************** NUMBER OF BYTES IN HEADER *******************************/

    strncpy(scratchpad, edf_hdr + 184, 8);
    scratchpad[8] = 0;

    for (i = 0; i < 8; i++) {
        if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    if (edflib_is_integer_number(scratchpad)) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    n = edflib_atoi_nonlocalized(scratchpad);
    if ((edfhdr->edfsignals * 256 + 256) != n) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

/********************* RESERVED FIELD *************************************/

    edfhdr->edfplus = 0;
    edfhdr->discontinuous = 0;
    strncpy(scratchpad, edf_hdr + 192, 44);
    scratchpad[44] = 0;

    for (i = 0; i < 44; i++) {
        if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    if (edfhdr->edf) {
        if (!strncmp(scratchpad, "EDF+C", 5)) {
            edfhdr->edfplus = 1;
        }

        if (!strncmp(scratchpad, "EDF+D", 5)) {
            edfhdr->edfplus = 1;
            edfhdr->discontinuous = 1;
        }
    }

    if (edfhdr->bdf) {
        if (!strncmp(scratchpad, "BDF+C", 5)) {
            edfhdr->bdfplus = 1;
        }

        if (!strncmp(scratchpad, "BDF+D", 5)) {
            edfhdr->bdfplus = 1;
            edfhdr->discontinuous = 1;
        }
    }

    strncpy(edfhdr->reserved, edf_hdr + 192, 44);
    edfhdr->reserved[44] = 0;

/********************* NUMBER OF DATARECORDS *************************************/

    strncpy(scratchpad, edf_hdr + 236, 8);
    scratchpad[8] = 0;

    for (i = 0; i < 8; i++) {
        if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    if (edflib_is_integer_number(scratchpad)) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    edfhdr->datarecords = edflib_atoi_nonlocalized(scratchpad);
    if (edfhdr->datarecords < 1) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

/********************* DATARECORD DURATION *************************************/

    strncpy(scratchpad, edf_hdr + 244, 8);
    scratchpad[8] = 0;

    for (i = 0; i < 8; i++) {
        if ((scratchpad[i] < 32) || (scratchpad[i] > 126)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr);
            return NULL;
        }
    }

    if (edflib_is_number(scratchpad)) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    edfhdr->data_record_duration = edflib_atof_nonlocalized(scratchpad);
    if (edfhdr->data_record_duration < -0.000001) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    edfhdr->long_data_record_duration = edflib_get_long_duration(scratchpad);

    free(edf_hdr);

/********************* START WITH THE SIGNALS IN THE HEADER *********************/

    edf_hdr = (char *) calloc(1, (edfhdr->edfsignals + 1) * 256);
    if (edf_hdr == NULL) {
        *edf_error = EDFLIB_MALLOC_ERROR;
        free(edfhdr);
        return NULL;
    }

    rewind(inputfile);
    if (fread(edf_hdr, (edfhdr->edfsignals + 1) * 256, 1, inputfile) != 1) {
        *edf_error = EDFLIB_FILE_READ_ERROR;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

    edfhdr->edfparam = (struct edfparamblock *) calloc(1, sizeof(struct edfparamblock) *
                                                          edfhdr->edfsignals);
    if (edfhdr->edfparam == NULL) {
        *edf_error = EDFLIB_MALLOC_ERROR;
        free(edf_hdr);
        free(edfhdr);
        return NULL;
    }

/**************************** LABELS *************************************/

    edfhdr->nr_annot_chns = 0;
    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (i * 16), 16);
        for (j = 0; j < 16; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }
        if (edfhdr->edfplus) {
            if (!strncmp(scratchpad, "EDF Annotations ", 16)) {
                edfhdr->annot_ch[edfhdr->nr_annot_chns] = i;
                edfhdr->nr_annot_chns++;
                edfhdr->edfparam[i].annotation = 1;
            }
        }
        if (edfhdr->bdfplus) {
            if (!strncmp(scratchpad, "BDF Annotations ", 16)) {
                edfhdr->annot_ch[edfhdr->nr_annot_chns] = i;
                edfhdr->nr_annot_chns++;
                edfhdr->edfparam[i].annotation = 1;
            }
        }
        strncpy(edfhdr->edfparam[i].label, edf_hdr + 256 + (i * 16), 16);
        edfhdr->edfparam[i].label[16] = 0;
    }
    if (edfhdr->edfplus && (!edfhdr->nr_annot_chns)) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr->edfparam);
        free(edfhdr);
        return NULL;
    }
    if (edfhdr->bdfplus && (!edfhdr->nr_annot_chns)) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr->edfparam);
        free(edfhdr);
        return NULL;
    }
    if ((edfhdr->edfsignals != edfhdr->nr_annot_chns) ||
        ((!edfhdr->edfplus) && (!edfhdr->bdfplus))) {
        if (edfhdr->data_record_duration < 0.0000001) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }
    }

/**************************** TRANSDUCER TYPES *************************************/

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 16) + (i * 80), 80);
        for (j = 0; j < 80; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }
        strncpy(edfhdr->edfparam[i].transducer,
                edf_hdr + 256 + (edfhdr->edfsignals * 16) + (i * 80), 80);
        edfhdr->edfparam[i].transducer[80] = 0;

        if ((edfhdr->edfplus) || (edfhdr->bdfplus)) {
            if (edfhdr->edfparam[i].annotation) {
                for (j = 0; j < 80; j++) {
                    if (edfhdr->edfparam[i].transducer[j] != ' ') {
                        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                        free(edf_hdr);
                        free(edfhdr->edfparam);
                        free(edfhdr);
                        return NULL;
                    }
                }
            }
        }
    }

/**************************** PHYSICAL DIMENSIONS *************************************/

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 96) + (i * 8), 8);
        for (j = 0; j < 8; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }
        strncpy(edfhdr->edfparam[i].physdimension,
                edf_hdr + 256 + (edfhdr->edfsignals * 96) + (i * 8), 8);
        edfhdr->edfparam[i].physdimension[8] = 0;
    }

/**************************** PHYSICAL MINIMUMS *************************************/

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 104) + (i * 8), 8);
        scratchpad[8] = 0;

        for (j = 0; j < 8; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }

        if (edflib_is_number(scratchpad)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }

        edfhdr->edfparam[i].phys_min = edflib_atof_nonlocalized(scratchpad);
    }

/**************************** PHYSICAL MAXIMUMS *************************************/

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 112) + (i * 8), 8);
        scratchpad[8] = 0;

        for (j = 0; j < 8; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }

        if (edflib_is_number(scratchpad)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }

        edfhdr->edfparam[i].phys_max = edflib_atof_nonlocalized(scratchpad);
        if (edfhdr->edfparam[i].phys_max == edfhdr->edfparam[i].phys_min) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }
    }

/**************************** DIGITAL MINIMUMS *************************************/

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 120) + (i * 8), 8);
        scratchpad[8] = 0;

        for (j = 0; j < 8; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }

        if (edflib_is_integer_number(scratchpad)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }

        n = edflib_atoi_nonlocalized(scratchpad);
        if (edfhdr->edfplus) {
            if (edfhdr->edfparam[i].annotation) {
                if (n != -0x8000) {
                    *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                    free(edf_hdr);
                    free(edfhdr->edfparam);
                    free(edfhdr);
                    return NULL;
                }
            }
        }
        if (edfhdr->bdfplus) {
            if (edfhdr->edfparam[i].annotation) {
                if (n != -0x800000) {
                    *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                    free(edf_hdr);
                    free(edfhdr->edfparam);
                    free(edfhdr);
                    return NULL;
                }
            }
        }
        if (edfhdr->edf) {
            if ((n > 0x7fff) || (n < -0x8000)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }
        if (edfhdr->bdf) {
            if ((n > 0x7fffff) || (n < -0x800000)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }
        edfhdr->edfparam[i].dig_min = n;
    }

/**************************** DIGITAL MAXIMUMS *************************************/

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 128) + (i * 8), 8);
        scratchpad[8] = 0;

        for (j = 0; j < 8; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }

        if (edflib_is_integer_number(scratchpad)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }

        n = edflib_atoi_nonlocalized(scratchpad);
        if (edfhdr->edfplus) {
            if (edfhdr->edfparam[i].annotation) {
                if (n != 0x7fff) {
                    *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                    free(edf_hdr);
                    free(edfhdr->edfparam);
                    free(edfhdr);
                    return NULL;
                }
            }
        }
        if (edfhdr->bdfplus) {
            if (edfhdr->edfparam[i].annotation) {
                if (n != 0x7fffff) {
                    *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                    free(edf_hdr);
                    free(edfhdr->edfparam);
                    free(edfhdr);
                    return NULL;
                }
            }
        }
        if (edfhdr->edf) {
            if ((n > 0x7fff) || (n < -0x8000)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        } else {
            if ((n > 0x7fffff) || (n < -0x800000)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }
        edfhdr->edfparam[i].dig_max = n;
        if (edfhdr->edfparam[i].dig_max < (edfhdr->edfparam[i].dig_min + 1)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }
    }

/**************************** PREFILTER FIELDS *************************************/

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 136) + (i * 80), 80);
        for (j = 0; j < 80; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }
        strncpy(edfhdr->edfparam[i].prefilter,
                edf_hdr + 256 + (edfhdr->edfsignals * 136) + (i * 80), 80);
        edfhdr->edfparam[i].prefilter[80] = 0;

        if ((edfhdr->edfplus) || (edfhdr->bdfplus)) {
            if (edfhdr->edfparam[i].annotation) {
                for (j = 0; j < 80; j++) {
                    if (edfhdr->edfparam[i].prefilter[j] != ' ') {
                        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                        free(edf_hdr);
                        free(edfhdr->edfparam);
                        free(edfhdr);
                        return NULL;
                    }
                }
            }
        }
    }

/*********************** NR OF SAMPLES IN EACH DATARECORD ********************/

    edfhdr->recordsize = 0;

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 216) + (i * 8), 8);
        scratchpad[8] = 0;

        for (j = 0; j < 8; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }

        if (edflib_is_integer_number(scratchpad)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }

        n = edflib_atoi_nonlocalized(scratchpad);
        if (n < 1) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }
        edfhdr->edfparam[i].smp_per_record = n;
        edfhdr->recordsize += n;
    }

    if (edfhdr->bdf) {
        edfhdr->recordsize *= 3;

        if (edfhdr->recordsize > (15 * 1024 * 1024)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }
    } else {
        edfhdr->recordsize *= 2;

        if (edfhdr->recordsize > (10 * 1024 * 1024)) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }
    }

/**************************** RESERVED FIELDS *************************************/

    for (i = 0; i < edfhdr->edfsignals; i++) {
        strncpy(scratchpad, edf_hdr + 256 + (edfhdr->edfsignals * 224) + (i * 32), 32);
        for (j = 0; j < 32; j++) {
            if ((scratchpad[j] < 32) || (scratchpad[j] > 126)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }
        strncpy(edfhdr->edfparam[i].reserved, edf_hdr + 256 + (edfhdr->edfsignals * 224) + (i * 32),
                32);
        edfhdr->edfparam[i].reserved[32] = 0;
    }

/********************* EDF+ PATIENTNAME *********************************************/

    if (edfhdr->edfplus || edfhdr->bdfplus) {
        error = 0;
        dotposition = 0;
        strncpy(scratchpad, edf_hdr + 8, 80);
        scratchpad[80] = 0;
        for (i = 0; i < 80; i++) {
            if (scratchpad[i] == ' ') {
                dotposition = i;
                break;
            }
        }
        dotposition++;
        if ((dotposition > 73) || (dotposition < 2)) error = 1;
        if (scratchpad[dotposition + 2] != 'X') {
            if (dotposition > 65) error = 1;
        }
        if ((scratchpad[dotposition] != 'M') && (scratchpad[dotposition] != 'F') &&
            (scratchpad[dotposition] != 'X'))
            error = 1;
        dotposition++;
        if (scratchpad[dotposition] != ' ') error = 1;
        if (scratchpad[dotposition + 1] == 'X') {
            if (scratchpad[dotposition + 2] != ' ') error = 1;
            if (scratchpad[dotposition + 3] == ' ') error = 1;
        } else {
            if (scratchpad[dotposition + 12] != ' ') error = 1;
            if (scratchpad[dotposition + 13] == ' ') error = 1;
            dotposition++;
            strncpy(scratchpad2, scratchpad + dotposition, 11);
            scratchpad2[11] = 0;
            if ((scratchpad2[2] != '-') || (scratchpad2[6] != '-')) error = 1;
            scratchpad2[2] = 0;
            scratchpad2[6] = 0;
            if ((scratchpad2[0] < 48) || (scratchpad2[0] > 57)) error = 1;
            if ((scratchpad2[1] < 48) || (scratchpad2[1] > 57)) error = 1;
            if ((scratchpad2[7] < 48) || (scratchpad2[7] > 57)) error = 1;
            if ((scratchpad2[8] < 48) || (scratchpad2[8] > 57)) error = 1;
            if ((scratchpad2[9] < 48) || (scratchpad2[9] > 57)) error = 1;
            if ((scratchpad2[10] < 48) || (scratchpad2[10] > 57)) error = 1;
            if ((edflib_atoi_nonlocalized(scratchpad2) < 1) ||
                (edflib_atoi_nonlocalized(scratchpad2) > 31))
                error = 1;
            if (strcmp(scratchpad2 + 3, "JAN"))
                if (strcmp(scratchpad2 + 3, "FEB"))
                    if (strcmp(scratchpad2 + 3, "MAR"))
                        if (strcmp(scratchpad2 + 3, "APR"))
                            if (strcmp(scratchpad2 + 3, "MAY"))
                                if (strcmp(scratchpad2 + 3, "JUN"))
                                    if (strcmp(scratchpad2 + 3, "JUL"))
                                        if (strcmp(scratchpad2 + 3, "AUG"))
                                            if (strcmp(scratchpad2 + 3, "SEP"))
                                                if (strcmp(scratchpad2 + 3, "OCT"))
                                                    if (strcmp(scratchpad2 + 3, "NOV"))
                                                        if (strcmp(scratchpad2 + 3, "DEC"))
                                                            error = 1;
        }

        if (error) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }

        p = 0;
        if ((edfhdr->patient[p] == 'X') && (edfhdr->patient[p + 1] == ' ')) {
            edfhdr->plus_patientcode[0] = 0;
            p += 2;
        } else {
            for (i = 0; i < (80 - p); i++) {
                if (edfhdr->patient[i + p] == ' ') {
                    break;
                }
                edfhdr->plus_patientcode[i] = edfhdr->patient[i + p];
                if (edfhdr->plus_patientcode[i] == '_') edfhdr->plus_patientcode[i] = ' ';
            }
            edfhdr->plus_patientcode[i] = 0;
            p += i + 1;
        }

        if (edfhdr->patient[p] == 'M') {
            edflib_strlcpy(edfhdr->plus_gender, "Male", 16);
        }
        if (edfhdr->patient[p] == 'F') {
            edflib_strlcpy(edfhdr->plus_gender, "Female", 16);
        }
        if (edfhdr->patient[p] == 'X') {
            edfhdr->plus_gender[0] = 0;
        }
        for (i = 0; i < (80 - p); i++) {
            if (edfhdr->patient[i + p] == ' ') {
                break;
            }
        }
        p += i + 1;

        if (edfhdr->patient[p] == 'X') {
            edfhdr->plus_birthdate[0] = 0;
            edfhdr->plus_birthdate_day = 0;
            edfhdr->plus_birthdate_month = 0;
            edfhdr->plus_birthdate_year = 0;
            p += 2;
        } else {
            for (i = 0; i < (80 - p); i++) {
                if (edfhdr->patient[i + p] == ' ') {
                    break;
                }
                edfhdr->plus_birthdate[i] = edfhdr->patient[i + p];
            }
            edfhdr->plus_birthdate[2] = ' ';
            edfhdr->plus_birthdate[3] += 32;
            edfhdr->plus_birthdate[4] += 32;
            edfhdr->plus_birthdate[5] += 32;
            edfhdr->plus_birthdate[6] = ' ';
            edfhdr->plus_birthdate[11] = 0;
            p += i + 1;
            edfhdr->plus_birthdate_day = edflib_atoi_nonlocalized(edfhdr->plus_birthdate);
            if (!strncmp(edfhdr->plus_birthdate + 3, "jan", 3)) {
                edfhdr->plus_birthdate_month = 1;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "feb", 3)) {
                edfhdr->plus_birthdate_month = 2;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "mar", 3)) {
                edfhdr->plus_birthdate_month = 3;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "apr", 3)) {
                edfhdr->plus_birthdate_month = 4;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "may", 3)) {
                edfhdr->plus_birthdate_month = 5;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "jun", 3)) {
                edfhdr->plus_birthdate_month = 6;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "jul", 3)) {
                edfhdr->plus_birthdate_month = 7;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "aug", 3)) {
                edfhdr->plus_birthdate_month = 8;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "sep", 3)) {
                edfhdr->plus_birthdate_month = 9;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "oct", 3)) {
                edfhdr->plus_birthdate_month = 10;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "nov", 3)) {
                edfhdr->plus_birthdate_month = 11;
            } else if (!strncmp(edfhdr->plus_birthdate + 3, "dec", 3)) {
                edfhdr->plus_birthdate_month = 12;
            } else {
                edfhdr->plus_birthdate_month = 0;
            }
            edfhdr->plus_birthdate_year = edflib_atoi_nonlocalized(edfhdr->plus_birthdate + 7);
        }

        for (i = 0; i < (80 - p); i++) {
            if (edfhdr->patient[i + p] == ' ') {
                break;
            }
            edfhdr->plus_patient_name[i] = edfhdr->patient[i + p];
            if (edfhdr->plus_patient_name[i] == '_') edfhdr->plus_patient_name[i] = ' ';
        }
        edfhdr->plus_patient_name[i] = 0;
        p += i + 1;

        for (i = 0; i < (80 - p); i++) {
            edfhdr->plus_patient_additional[i] = edfhdr->patient[i + p];
        }
        edfhdr->plus_patient_additional[i] = 0;
        p += i + 1;
    }

/********************* EDF+ RECORDINGFIELD *********************************************/

    if (edfhdr->edfplus || edfhdr->bdfplus) {
        error = 0;
        strncpy(scratchpad, edf_hdr + 88, 80);
        scratchpad[80] = 0;
        if (strncmp(scratchpad, "Startdate ", 10)) error = 1;
        if (scratchpad[10] == 'X') {
            if (scratchpad[11] != ' ') error = 1;
            if (scratchpad[12] == ' ') error = 1;
            p = 12;
        } else {
            if (scratchpad[21] != ' ') error = 1;
            if (scratchpad[22] == ' ') error = 1;
            p = 22;
            strncpy(scratchpad2, scratchpad + 10, 11);
            scratchpad2[11] = 0;
            if ((scratchpad2[2] != '-') || (scratchpad2[6] != '-')) error = 1;
            scratchpad2[2] = 0;
            scratchpad2[6] = 0;
            if ((scratchpad2[0] < 48) || (scratchpad2[0] > 57)) error = 1;
            if ((scratchpad2[1] < 48) || (scratchpad2[1] > 57)) error = 1;
            if ((scratchpad2[7] < 48) || (scratchpad2[7] > 57)) error = 1;
            if ((scratchpad2[8] < 48) || (scratchpad2[8] > 57)) error = 1;
            if ((scratchpad2[9] < 48) || (scratchpad2[9] > 57)) error = 1;
            if ((scratchpad2[10] < 48) || (scratchpad2[10] > 57)) error = 1;
            if ((edflib_atoi_nonlocalized(scratchpad2) < 1) ||
                (edflib_atoi_nonlocalized(scratchpad2) > 31))
                error = 1;
            r = 0;
            if (!strcmp(scratchpad2 + 3, "JAN")) r = 1;
            else if (!strcmp(scratchpad2 + 3, "FEB")) r = 2;
            else if (!strcmp(scratchpad2 + 3, "MAR")) r = 3;
            else if (!strcmp(scratchpad2 + 3, "APR")) r = 4;
            else if (!strcmp(scratchpad2 + 3, "MAY")) r = 5;
            else if (!strcmp(scratchpad2 + 3, "JUN")) r = 6;
            else if (!strcmp(scratchpad2 + 3, "JUL")) r = 7;
            else if (!strcmp(scratchpad2 + 3, "AUG")) r = 8;
            else if (!strcmp(scratchpad2 + 3, "SEP")) r = 9;
            else if (!strcmp(scratchpad2 + 3, "OCT")) r = 10;
            else if (!strcmp(scratchpad2 + 3, "NOV")) r = 11;
            else if (!strcmp(scratchpad2 + 3, "DEC")) r = 12;
            else error = 1;
        }

        n = 0;
        for (i = p; i < 80; i++) {
            if (i > 78) {
                error = 1;
                break;
            }
            if (scratchpad[i] == ' ') {
                n++;
                if (scratchpad[i + 1] == ' ') {
                    error = 1;
                    break;
                }
            }
            if (n > 1) break;
        }

        if (error) {
            *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
            free(edf_hdr);
            free(edfhdr->edfparam);
            free(edfhdr);
            return NULL;
        }

        if (edf_hdr[98] != 'X') {
            error = 0;

            strncpy(scratchpad, edf_hdr + 168, 8);
            scratchpad[2] = 0;
            scratchpad[5] = 0;
            scratchpad[8] = 0;

            if (edflib_atoi_nonlocalized(scratchpad) != edflib_atoi_nonlocalized(scratchpad2))
                error = 1;
            if (edflib_atoi_nonlocalized(scratchpad + 3) != r) error = 1;
            if (edflib_atoi_nonlocalized(scratchpad + 6) !=
                edflib_atoi_nonlocalized(scratchpad2 + 9))
                error = 1;
            if (error) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }

            if (edfhdr->startdate_year != edflib_atoi_nonlocalized(scratchpad2 + 7)) {
                *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
                free(edf_hdr);
                free(edfhdr->edfparam);
                free(edfhdr);
                return NULL;
            }
        }

        p = 10;
        for (i = 0; i < (80 - p); i++) {
            if (edfhdr->recording[i + p] == ' ') {
                break;
            }
            edfhdr->plus_startdate[i] = edfhdr->recording[i + p];
        }
        edfhdr->plus_startdate[2] = ' ';
        edfhdr->plus_startdate[3] += 32;
        edfhdr->plus_startdate[4] += 32;
        edfhdr->plus_startdate[5] += 32;
        edfhdr->plus_startdate[6] = ' ';
        edfhdr->plus_startdate[11] = 0;
        p += i + 1;

        if ((edfhdr->recording[p] == 'X') && (edfhdr->recording[p + 1] == ' ')) {
            edfhdr->plus_admincode[0] = 0;
            p += 2;
        } else {
            for (i = 0; i < (80 - p); i++) {
                if (edfhdr->recording[i + p] == ' ') {
                    break;
                }
                edfhdr->plus_admincode[i] = edfhdr->recording[i + p];
                if (edfhdr->plus_admincode[i] == '_') edfhdr->plus_admincode[i] = ' ';
            }
            edfhdr->plus_admincode[i] = 0;
            p += i + 1;
        }

        if ((edfhdr->recording[p] == 'X') && (edfhdr->recording[p + 1] == ' ')) {
            edfhdr->plus_technician[0] = 0;
            p += 2;
        } else {
            for (i = 0; i < (80 - p); i++) {
                if (edfhdr->recording[i + p] == ' ') {
                    break;
                }
                edfhdr->plus_technician[i] = edfhdr->recording[i + p];
                if (edfhdr->plus_technician[i] == '_') edfhdr->plus_technician[i] = ' ';
            }
            edfhdr->plus_technician[i] = 0;
            p += i + 1;
        }

        if ((edfhdr->recording[p] == 'X') && (edfhdr->recording[p + 1] == ' ')) {
            edfhdr->plus_equipment[0] = 0;
            p += 2;
        } else {
            for (i = 0; i < (80 - p); i++) {
                if (edfhdr->recording[i + p] == ' ') {
                    break;
                }
                edfhdr->plus_equipment[i] = edfhdr->recording[i + p];
                if (edfhdr->plus_equipment[i] == '_') edfhdr->plus_equipment[i] = ' ';
            }
            edfhdr->plus_equipment[i] = 0;
            p += i + 1;
        }

        for (i = 0; i < (80 - p); i++) {
            edfhdr->plus_recording_additional[i] = edfhdr->recording[i + p];
        }
        edfhdr->plus_recording_additional[i] = 0;
        p += i + 1;
    }

/********************* FILESIZE *********************************************/

    edfhdr->hdrsize = edfhdr->edfsignals * 256 + 256;

    fseeko(inputfile, 0LL, SEEK_END);
    if (ftello(inputfile) != (edfhdr->recordsize * edfhdr->datarecords + edfhdr->hdrsize)) {
        *edf_error = EDFLIB_FILE_CONTAINS_FORMAT_ERRORS;
        free(edf_hdr);
        free(edfhdr->edfparam);
        free(edfhdr);
        return NULL;
    }

    n = 0;

    for (i = 0; i < edfhdr->edfsignals; i++) {
        edfhdr->edfparam[i].buf_offset = n;
        if (edfhdr->bdf) n += edfhdr->edfparam[i].smp_per_record * 3;
        else n += edfhdr->edfparam[i].smp_per_record * 2;

        edfhdr->edfparam[i].bitvalue =
                (edfhdr->edfparam[i].phys_max - edfhdr->edfparam[i].phys_min) /
                (edfhdr->edfparam[i].dig_max - edfhdr->edfparam[i].dig_min);
        edfhdr->edfparam[i].offset = edfhdr->edfparam[i].phys_max / edfhdr->edfparam[i].bitvalue -
                                     edfhdr->edfparam[i].dig_max;
    }

    edfhdr->file_hdl = inputfile;

    free(edf_hdr);

    return edfhdr;
}


static int edflib_is_integer_number(char *str) {
    int i = 0, l, hasspace = 0, hassign = 0, digit = 0;

    l = strlen(str);

    if (!l) return 1;

    if ((str[0] == '+') || (str[0] == '-')) {
        hassign++;
        i++;
    }

    for (; i < l; i++) {
        if (str[i] == ' ') {
            if (!digit) {
                return 1;
            }
            hasspace++;
        } else {
            if ((str[i] < 48) || (str[i] > 57)) {
                return 1;
            } else {
                if (hasspace) {
                    return 1;
                }
                digit++;
            }
        }
    }

    if (digit) return 0;
    else return 1;
}


static int edflib_is_number(char *str) {
    int i = 0, l, hasspace = 0, hassign = 0, digit = 0, hasdot = 0, hasexp = 0;

    l = strlen(str);

    if (!l) return 1;

    if ((str[0] == '+') || (str[0] == '-')) {
        hassign++;
        i++;
    }

    for (; i < l; i++) {
        if ((str[i] == 'e') || (str[i] == 'E')) {
            if ((!digit) || hasexp) {
                return 1;
            }
            hasexp++;
            hassign = 0;
            digit = 0;

            break;
        }

        if (str[i] == ' ') {
            if (!digit) {
                return 1;
            }
            hasspace++;
        } else {
            if (((str[i] < 48) || (str[i] > 57)) && str[i] != '.') {
                return 1;
            } else {
                if (hasspace) {
                    return 1;
                }
                if (str[i] == '.') {
                    if (hasdot) return 1;
                    hasdot++;
                } else {
                    digit++;
                }
            }
        }
    }

    if (hasexp) {
        if (++i == l) {
            return 1;
        }

        if ((str[i] == '+') || (str[i] == '-')) {
            hassign++;
            i++;
        }

        for (; i < l; i++) {
            if (str[i] == ' ') {
                if (!digit) {
                    return 1;
                }
                hasspace++;
            } else {
                if ((str[i] < 48) || (str[i] > 57)) {
                    return 1;
                } else {
                    if (hasspace) {
                        return 1;
                    }

                    digit++;
                }
            }
        }
    }

    if (digit) return 0;
    else return 1;
}


static long long edflib_get_long_duration(char *str) {
    int i, len = 8, hasdot = 0, dotposition = 0;

    long long value = 0, radix;

    if ((str[0] == '+') || (str[0] == '-')) {
        for (i = 0; i < 7; i++) {
            str[i] = str[i + 1];
        }

        str[7] = ' ';
    }

    for (i = 0; i < 8; i++) {
        if (str[i] == ' ') {
            len = i;
            break;
        }
    }

    for (i = 0; i < len; i++) {
        if (str[i] == '.') {
            hasdot = 1;
            dotposition = i;
            break;
        }
    }

    if (hasdot) {
        radix = EDFLIB_TIME_DIMENSION;

        for (i = dotposition - 1; i >= 0; i--) {
            value += ((long long) (str[i] - 48)) * radix;
            radix *= 10;
        }

        radix = EDFLIB_TIME_DIMENSION / 10;

        for (i = dotposition + 1; i < len; i++) {
            value += ((long long) (str[i] - 48)) * radix;
            radix /= 10;
        }
    } else {
        radix = EDFLIB_TIME_DIMENSION;

        for (i = len - 1; i >= 0; i--) {
            value += ((long long) (str[i] - 48)) * radix;
            radix *= 10;
        }
    }

    return value;
}


int edflib_version(void) {
    return EDFLIB_VERSION;
}


static int edflib_get_annotations(struct edfhdrblock *edfhdr, int hdl, int read_annotations_mode) {
    int i, j, k, p, r = 0, n,
            edfsignals,
            datarecords,
            recordsize,
            discontinuous,
            *annot_ch,
            nr_annot_chns,
            max,
            onset,
            duration,
            duration_start,
            zero,
            max_tal_ln,
            error,
            annots_in_record,
            annots_in_tal,
            samplesize = 2;

    char *scratchpad,
            *cnv_buf,
            *time_in_txt,
            *duration_in_txt;


    long long data_record_duration,
            elapsedtime,
            time_tmp = 0;

    FILE *inputfile;

    struct edfparamblock *edfparam;

    struct edf_annotationblock *new_annotation = NULL,
            *malloc_list;

    inputfile = edfhdr->file_hdl;
    edfsignals = edfhdr->edfsignals;
    recordsize = edfhdr->recordsize;
    edfparam = edfhdr->edfparam;
    nr_annot_chns = edfhdr->nr_annot_chns;
    datarecords = edfhdr->datarecords;
    data_record_duration = edfhdr->long_data_record_duration;
    discontinuous = edfhdr->discontinuous;
    annot_ch = edfhdr->annot_ch;

    if (edfhdr->edfplus) {
        samplesize = 2;
    }
    if (edfhdr->bdfplus) {
        samplesize = 3;
    }

    cnv_buf = (char *) calloc(1, recordsize);
    if (cnv_buf == NULL) {
        return 1;
    }

    max_tal_ln = 0;

    for (i = 0; i < nr_annot_chns; i++) {
        if (max_tal_ln < edfparam[annot_ch[i]].smp_per_record * samplesize)
            max_tal_ln = edfparam[annot_ch[i]].smp_per_record * samplesize;
    }

    if (max_tal_ln < 128) max_tal_ln = 128;

    scratchpad = (char *) calloc(1, max_tal_ln + 3);
    if (scratchpad == NULL) {
        free(cnv_buf);
        return 1;
    }

    time_in_txt = (char *) calloc(1, max_tal_ln + 3);
    if (time_in_txt == NULL) {
        free(cnv_buf);
        free(scratchpad);
        return 1;
    }

    duration_in_txt = (char *) calloc(1, max_tal_ln + 3);
    if (duration_in_txt == NULL) {
        free(cnv_buf);
        free(scratchpad);
        free(time_in_txt);
        return 1;
    }

    if (fseeko(inputfile, (long long) ((edfsignals + 1) * 256), SEEK_SET)) {
        free(cnv_buf);
        free(scratchpad);
        free(time_in_txt);
        free(duration_in_txt);
        return 2;
    }

    elapsedtime = 0;

    for (i = 0; i < datarecords; i++) {
        if (fread(cnv_buf, recordsize, 1, inputfile) != 1) {
            free(cnv_buf);
            free(scratchpad);
            free(time_in_txt);
            free(duration_in_txt);
            return 2;
        }


/************** process annotationsignals (if any) **************/

        error = 0;

        for (r = 0; r < nr_annot_chns; r++) {
            n = 0;
            zero = 0;
            onset = 0;
            duration = 0;
            duration_start = 0;
            scratchpad[0] = 0;
            annots_in_tal = 0;
            annots_in_record = 0;

            p = edfparam[annot_ch[r]].buf_offset;
            max = edfparam[annot_ch[r]].smp_per_record * samplesize;

/************** process one annotation signal ****************/

            if (cnv_buf[p + max - 1] != 0) {
                error = 5;
                goto END;
            }

            if (!r)  /* if it's the first annotation signal, then check */
            {       /* the timekeeping annotation */
                error = 1;

                for (k = 0; k < (max - 2); k++) {
                    scratchpad[k] = cnv_buf[p + k];

                    if (scratchpad[k] == 20) {
                        if (cnv_buf[p + k + 1] != 20) {
                            error = 6;
                            goto END;
                        }
                        scratchpad[k] = 0;
                        if (edflib_is_onset_number(scratchpad)) {
                            error = 36;
                            goto END;
                        } else {
                            time_tmp = edflib_get_long_time(scratchpad);
                            if (i) {
                                if (discontinuous) {
                                    if ((time_tmp - elapsedtime) < data_record_duration) {
                                        error = 4;
                                        goto END;
                                    }
                                } else {
                                    if ((time_tmp - elapsedtime) != data_record_duration) {
                                        error = 3;
                                        goto END;
                                    }
                                }
                            } else {
                                if ((time_tmp >= EDFLIB_TIME_DIMENSION) || (time_tmp < 0LL)) {
                                    error = 2;
                                    goto END;
                                } else {
                                    edfhdr->starttime_offset = time_tmp;
                                    if (read_annotations_mode == EDFLIB_DO_NOT_READ_ANNOTATIONS) {
                                        error = 0;
                                        goto END_OUT;
                                    }
                                }
                            }
                            elapsedtime = time_tmp;
                            error = 0;
                            break;
                        }
                    }
                }
            }

            for (k = 0; k < max; k++) {
                scratchpad[n] = cnv_buf[p + k];

                if (!scratchpad[n]) {
                    if (!zero) {
                        if (k) {
                            if (cnv_buf[p + k - 1] != 20) {
                                error = 33;
                                goto END;
                            }
                        }
                        n = 0;
                        onset = 0;
                        duration = 0;
                        duration_start = 0;
                        scratchpad[0] = 0;
                        annots_in_tal = 0;
                    }
                    zero++;
                    continue;
                }
                if (zero > 1) {
                    error = 34;
                    goto END;
                }
                zero = 0;

                if ((scratchpad[n] == 20) || (scratchpad[n] == 21)) {
                    if (scratchpad[n] == 21) {
                        if (duration || duration_start || onset ||
                            annots_in_tal) {               /* it's not allowed to have multiple duration fields */
                            error = 35;   /* in one TAL or to have a duration field which is   */
                            goto END;     /* not immediately behind the onsetfield             */
                        }
                        duration_start = 1;
                    }

                    if ((scratchpad[n] == 20) && onset && (!duration_start)) {
                        if (r || annots_in_record) {
                            if (n >= 0) {
                                if (edfhdr->annots_in_file >= edfhdr->annotlist_sz) {
                                    malloc_list = (struct edf_annotationblock *) realloc(
                                            annotationslist[hdl],
                                            sizeof(struct edf_annotationblock) *
                                            (edfhdr->annotlist_sz + EDFLIB_ANNOT_MEMBLOCKSZ));
                                    if (malloc_list == NULL) {
                                        free(cnv_buf);
                                        free(scratchpad);
                                        free(time_in_txt);
                                        free(duration_in_txt);
                                        return -1;
                                    }

                                    annotationslist[hdl] = malloc_list;

                                    edfhdr->annotlist_sz += EDFLIB_ANNOT_MEMBLOCKSZ;
                                }

                                new_annotation = annotationslist[hdl] + edfhdr->annots_in_file;

                                new_annotation->annotation[0] = 0;

                                if (duration) {
                                    edflib_strlcpy(new_annotation->duration, duration_in_txt, 16);
                                    new_annotation->duration_l = edflib_get_long_time(
                                            duration_in_txt);
                                } else {
                                    new_annotation->duration[0] = 0;
                                    new_annotation->duration_l = -EDFLIB_TIME_DIMENSION;
                                }

                                for (j = 0; j < n; j++) {
                                    if (j == EDFLIB_MAX_ANNOTATION_LEN) break;
                                    new_annotation->annotation[j] = scratchpad[j];
                                }
                                new_annotation->annotation[j] = 0;

                                new_annotation->onset = edflib_get_long_time(time_in_txt);

                                new_annotation->onset -= edfhdr->starttime_offset;

                                edfhdr->annots_in_file++;

                                if (read_annotations_mode == EDFLIB_READ_ANNOTATIONS) {
                                    if (!(strncmp(new_annotation->annotation, "Recording ends",
                                                  14))) {
                                        if (nr_annot_chns == 1) {
                                            goto END;
                                        }
                                    }
                                }
                            }
                        }

                        annots_in_tal++;
                        annots_in_record++;
                        n = 0;
                        continue;
                    }

                    if (!onset) {
                        scratchpad[n] = 0;
                        if (edflib_is_onset_number(scratchpad)) {
                            error = 36;
                            goto END;
                        }
                        onset = 1;
                        n = 0;
                        edflib_strlcpy(time_in_txt, scratchpad, max_tal_ln + 3);
                        continue;
                    }

                    if (duration_start) {
                        scratchpad[n] = 0;
                        if (edflib_is_duration_number(scratchpad)) {
                            error = 37;
                            goto END;
                        }

                        for (j = 0; j < n; j++) {
                            if (j == 15) break;
                            duration_in_txt[j] = scratchpad[j];
                            if ((duration_in_txt[j] < 32) || (duration_in_txt[j] > 126)) {
                                duration_in_txt[j] = '.';
                            }
                        }
                        duration_in_txt[j] = 0;

                        duration = 1;
                        duration_start = 0;
                        n = 0;
                        continue;
                    }
                }

                n++;
            }

            END:

/****************** end ************************/

            if (error) {
                free(cnv_buf);
                free(scratchpad);
                free(time_in_txt);
                free(duration_in_txt);
                return 9;
            }
        }
    }

    END_OUT:

    free(cnv_buf);
    free(scratchpad);
    free(time_in_txt);
    free(duration_in_txt);

    return 0;
}


static int edflib_is_duration_number(char *str) {
    int i, l, hasdot = 0;

    l = strlen(str);

    if (!l) return 1;

    if ((str[0] == '.') || (str[l - 1] == '.')) return 1;

    for (i = 0; i < l; i++) {
        if (str[i] == '.') {
            if (hasdot) return 1;
            hasdot++;
        } else {
            if ((str[i] < 48) || (str[i] > 57)) return 1;
        }
    }

    return 0;
}


static int edflib_is_onset_number(char *str) {
    int i, l, hasdot = 0;

    l = strlen(str);

    if (l < 2) return 1;

    if ((str[0] != '+') && (str[0] != '-')) return 1;

    if ((str[1] == '.') || (str[l - 1] == '.')) return 1;

    for (i = 1; i < l; i++) {
        if (str[i] == '.') {
            if (hasdot) return 1;
            hasdot++;
        } else {
            if ((str[i] < 48) || (str[i] > 57)) return 1;
        }
    }

    return 0;
}


static long long edflib_get_long_time(char *str) {
    int i, len, hasdot = 0, dotposition = 0, neg = 0;

    long long value = 0, radix;

    if (str[0] == '+') {
        str++;
    } else if (str[0] == '-') {
        neg = 1;
        str++;
    }

    len = strlen(str);

    for (i = 0; i < len; i++) {
        if (str[i] == '.') {
            hasdot = 1;
            dotposition = i;
            break;
        }
    }

    if (hasdot) {
        radix = EDFLIB_TIME_DIMENSION;

        for (i = dotposition - 1; i >= 0; i--) {
            value += ((long long) (str[i] - 48)) * radix;
            radix *= 10;
        }

        radix = EDFLIB_TIME_DIMENSION / 10;

        for (i = dotposition + 1; i < len; i++) {
            value += ((long long) (str[i] - 48)) * radix;
            radix /= 10;
        }
    } else {
        radix = EDFLIB_TIME_DIMENSION;

        for (i = len - 1; i >= 0; i--) {
            value += ((long long) (str[i] - 48)) * radix;
            radix *= 10;
        }
    }

    if (neg) value = -value;

    return value;
}


static void edflib_latin1_to_ascii(char *str, int len) {
    /* ISO 8859-1 except for characters 0x80 to 0x9f which are taken from the extension CP-1252 */

    int i, value;

    const char conv_table[] = ".E.,F\".++^.S<E.Z..`\'\"\".--~.s>e.zY.i....|....<...-....\'u.....>...?AAAAAAECEEEEIIIIDNOOOOOxOUUUUYtsaaaaaaeceeeeiiiidnooooo:0uuuuyty";

    for (i = 0; i < len; i++) {
        value = *((unsigned char *) (str + i));

        if ((value > 31) && (value < 127)) {
            continue;
        }

        if (value < 32) {
            str[i] = '.';

            continue;
        }

        str[i] = conv_table[value - 127];
    }
}


static void edflib_latin12utf8(char *latin1_str, int len) {
    int i, j;

    unsigned char *str, tmp_str[512];


    str = (unsigned char *) latin1_str;

    j = 0;

    for (i = 0; i < len; i++) {
        if (str[i] == 0) {
            tmp_str[j] = 0;

            break;
        }

        tmp_str[j] = str[i];

        if (str[i] < 32) tmp_str[j] = '.';

        if ((str[i] > 126) && (str[i] < 160)) tmp_str[j] = '.';

        if (str[i] > 159) {
            if ((len - j) < 2) {
                tmp_str[j] = ' ';
            } else {
                tmp_str[j] = 192 + (str[i] >> 6);
                j++;
                tmp_str[j] = 128 + (str[i] & 63);
            }
        }

        j++;

        if (j >= len) break;
    }

    for (i = 0; i < len; i++) {
        str[i] = tmp_str[i];
    }
}


int edfopen_file_writeonly_with_params(const char *path, int filetype, int number_of_signals,
                                       int samplefrequency, double phys_max_min,
                                       const char *phys_dim) {
    int i, handle;

    char str[32] = "";

    handle = edfopen_file_writeonly(path, filetype, number_of_signals);
    if (handle < 0) {
        return handle;
    }

    for (i = 0; i < number_of_signals; i++) {
        if (edf_set_samplefrequency(handle, i, samplefrequency)) {
            edfclose_file(handle);
            return -1;
        }

        if (edf_set_physical_maximum(handle, i, phys_max_min)) {
            edfclose_file(handle);
            return -1;
        }

        if (edf_set_physical_minimum(handle, i, -phys_max_min)) {
            edfclose_file(handle);
            return -1;
        }

        if (edf_set_physical_dimension(handle, i, phys_dim)) {
            edfclose_file(handle);
            return -1;
        }

        snprintf(str, 32, "chan. %i", i + 1);

        if (edf_set_label(handle, i, str)) {
            edfclose_file(handle);
            return -1;
        }

        if (filetype == EDFLIB_FILETYPE_BDFPLUS) {
            if (edf_set_digital_maximum(handle, i, 0x7fffff)) {
                edfclose_file(handle);
                return -1;
            }

            if (edf_set_digital_minimum(handle, i, -0x800000)) {
                edfclose_file(handle);
                return -1;
            }
        } else {
            if (edf_set_digital_maximum(handle, i, 0x7fff)) {
                edfclose_file(handle);
                return -1;
            }

            if (edf_set_digital_minimum(handle, i, -0x8000)) {
                edfclose_file(handle);
                return -1;
            }
        }
    }

    return handle;
}


int edfopen_file_writeonly(const char *path, int filetype, int number_of_signals) {
    int i, handle;

    FILE *file;

    struct edfhdrblock *hdr;

    union {
        char four[4];
        int one;
    } byte_order_test_var;

    /* avoid surprises! */
    if ((sizeof(char) != 1) ||
        (sizeof(short) != 2) ||
        (sizeof(int) != 4) ||
        (sizeof(long long) != 8) ||
        (sizeof(float) != 4) ||
        (sizeof(double) != 8)) {
        return EDFLIB_ARCH_ERROR;
    }

    /* check endianness! */
    byte_order_test_var.one = 0x03020100;
    if ((byte_order_test_var.four[0] != 0) ||
        (byte_order_test_var.four[1] != 1) ||
        (byte_order_test_var.four[2] != 2) ||
        (byte_order_test_var.four[3] != 3)) {
        return EDFLIB_ARCH_ERROR;
    }

    if ((filetype != EDFLIB_FILETYPE_EDFPLUS) && (filetype != EDFLIB_FILETYPE_BDFPLUS)) {
        return EDFLIB_FILETYPE_ERROR;
    }

    if (edf_files_open >= EDFLIB_MAXFILES) {
        return EDFLIB_MAXFILES_REACHED;
    }

    for (i = 0; i < EDFLIB_MAXFILES; i++) {
        if (hdrlist[i] != NULL) {
            if (!(strcmp(path, hdrlist[i]->path))) {
                return EDFLIB_FILE_ALREADY_OPENED;
            }
        }
    }

    if (number_of_signals < 0) {
        return EDFLIB_NUMBER_OF_SIGNALS_INVALID;
    }

    if (number_of_signals > EDFLIB_MAXSIGNALS) {
        return EDFLIB_NUMBER_OF_SIGNALS_INVALID;
    }

    hdr = (struct edfhdrblock *) calloc(1, sizeof(struct edfhdrblock));
    if (hdr == NULL) {
        return EDFLIB_MALLOC_ERROR;
    }

    hdr->edfparam = (struct edfparamblock *) calloc(1, sizeof(struct edfparamblock) *
                                                       number_of_signals);
    if (hdr->edfparam == NULL) {
        free(hdr);

        return EDFLIB_MALLOC_ERROR;
    }

    hdr->writemode = 1;

    hdr->edfsignals = number_of_signals;

    handle = -1;

    for (i = 0; i < EDFLIB_MAXFILES; i++) {
        if (hdrlist[i] == NULL) {
            hdrlist[i] = hdr;

            handle = i;

            break;
        }
    }

    if (handle < 0) {
        free(hdr->edfparam);

        free(hdr);

        return EDFLIB_MAXFILES_REACHED;
    }

    write_annotationslist[handle] = NULL;

    hdr->annotlist_sz = 0;

    hdr->annots_in_file = 0;

    file = fopeno(path, "wb");
    if (file == NULL) {
        free(hdr->edfparam);
        hdr->edfparam = NULL;
        free(hdr);
        hdr = NULL;
        hdrlist[handle] = NULL;

        return EDFLIB_NO_SUCH_FILE_OR_DIRECTORY;
    }

    hdr->file_hdl = file;

    edflib_strlcpy(hdr->path, path, 1024);

    edf_files_open++;

    if (filetype == EDFLIB_FILETYPE_EDFPLUS) {
        hdr->edf = 1;
        hdr->edfplus = 1;
    }

    if (filetype == EDFLIB_FILETYPE_BDFPLUS) {
        hdr->bdf = 1;
        hdr->bdfplus = 1;
    }

    hdr->long_data_record_duration = EDFLIB_TIME_DIMENSION;

    hdr->data_record_duration = 1.0;

    hdr->nr_annot_chns = 1;

    return handle;
}


int edf_set_samplefrequency(int handle, int edfsignal, int samplefrequency) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (edfsignal < 0) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (edfsignal >= hdrlist[handle]->edfsignals) return -1;

    if (samplefrequency < 1) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    hdrlist[handle]->edfparam[edfsignal].smp_per_record = samplefrequency;

    return 0;
}


int edf_set_number_of_annotation_signals(int handle, int annot_signals) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((annot_signals < 1) || (annot_signals > EDFLIB_MAX_ANNOTATION_CHANNELS)) return -1;

    hdrlist[handle]->nr_annot_chns = annot_signals;

    return 0;
}


int edf_set_datarecord_duration(int handle, int duration) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((duration < 100) || (duration > 6000000)) return -1;

    hdrlist[handle]->long_data_record_duration = (long long) duration * 100LL;

    if (hdrlist[handle]->long_data_record_duration < (EDFLIB_TIME_DIMENSION * 10LL)) {
        hdrlist[handle]->long_data_record_duration /= 10LL;

        hdrlist[handle]->long_data_record_duration *= 10LL;
    } else {
        hdrlist[handle]->long_data_record_duration /= 100LL;

        hdrlist[handle]->long_data_record_duration *= 100LL;
    }

    hdrlist[handle]->data_record_duration =
            ((double) (hdrlist[handle]->long_data_record_duration)) / EDFLIB_TIME_DIMENSION;

    return 0;
}


int edf_set_micro_datarecord_duration(int handle, int duration) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((duration < 1) || (duration > 9999)) return -1;

    hdrlist[handle]->long_data_record_duration = (long long) duration * 10LL;

    hdrlist[handle]->data_record_duration =
            ((double) (hdrlist[handle]->long_data_record_duration)) / EDFLIB_TIME_DIMENSION;

    return 0;
}


int edf_set_subsecond_starttime(int handle, int subsecond) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((subsecond < 0) || (subsecond > 9999999)) return -1;

    hdrlist[handle]->starttime_offset = (long long) subsecond;

    return 0;
}


int edfwrite_digital_short_samples(int handle, short *buf) {
    int i,
            error,
            sf,
            digmax,
            digmin,
            edfsignal,
            value;

    FILE *file;

    struct edfhdrblock *hdr;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->edfsignals == 0) return -1;

    if (hdrlist[handle]->bdf == 1) return -1;

    hdr = hdrlist[handle];

    file = hdr->file_hdl;

    edfsignal = hdr->signal_write_sequence_pos;

    if (!hdr->datarecords) {
        if (!edfsignal) {
            error = edflib_write_edf_header(hdr);

            if (error) return error;
        }
    }

    sf = hdr->edfparam[edfsignal].smp_per_record;

    digmax = hdr->edfparam[edfsignal].dig_max;

    digmin = hdr->edfparam[edfsignal].dig_min;

    if (hdr->edf) {
        if ((digmax != 0x7fff) || (digmin != -0x8000)) {
            for (i = 0; i < sf; i++) {
                if (buf[i] > digmax) buf[i] = digmax;

                if (buf[i] < digmin) buf[i] = digmin;
            }
        }

        if (fwrite(buf, sf * 2, 1, file) != 1) return -1;
    } else  // BDF
    {
        if (hdr->wrbufsize < (sf * 3)) {
            free(hdr->wrbuf);

            hdr->wrbufsize = 0;

            hdr->wrbuf = (char *) malloc(sf * 3);

            if (hdr->wrbuf == NULL) return -1;

            hdr->wrbufsize = sf * 3;
        }

        for (i = 0; i < sf; i++) {
            value = buf[i];

            if (value > digmax) value = digmax;

            if (value < digmin) value = digmin;

            hdr->wrbuf[i * 3] = value & 0xff;

            hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;

            hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
        }

        if (fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
    }

    hdr->signal_write_sequence_pos++;

    if (hdr->signal_write_sequence_pos == hdr->edfsignals) {
        hdr->signal_write_sequence_pos = 0;

        if (edflib_write_tal(hdr, file)) return -1;

        hdr->datarecords++;

        fflush(file);
    }

    return 0;
}


int edfwrite_digital_samples(int handle, int *buf) {
    int i,
            error,
            sf,
            digmax,
            digmin,
            edfsignal,
            value;

    FILE *file;

    struct edfhdrblock *hdr;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->edfsignals == 0) return -1;

    hdr = hdrlist[handle];

    file = hdr->file_hdl;

    edfsignal = hdr->signal_write_sequence_pos;

    if (!hdr->datarecords) {
        if (!edfsignal) {
            error = edflib_write_edf_header(hdr);

            if (error) return error;
        }
    }

    sf = hdr->edfparam[edfsignal].smp_per_record;

    digmax = hdr->edfparam[edfsignal].dig_max;

    digmin = hdr->edfparam[edfsignal].dig_min;

    if (hdr->edf) {
        if (hdr->wrbufsize < (sf * 2)) {
            free(hdr->wrbuf);

            hdr->wrbufsize = 0;

            hdr->wrbuf = (char *) malloc(sf * 2);

            if (hdr->wrbuf == NULL) return -1;

            hdr->wrbufsize = sf * 2;
        }

        for (i = 0; i < sf; i++) {
            value = buf[i];

            if (value > digmax) value = digmax;

            if (value < digmin) value = digmin;

            hdr->wrbuf[i * 2] = value & 0xff;

            hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff;
        }

        if (fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1;
    } else  // BDF
    {
        if (hdr->wrbufsize < (sf * 3)) {
            free(hdr->wrbuf);

            hdr->wrbufsize = 0;

            hdr->wrbuf = (char *) malloc(sf * 3);

            if (hdr->wrbuf == NULL) return -1;

            hdr->wrbufsize = sf * 3;
        }

        for (i = 0; i < sf; i++) {
            value = buf[i];

            if (value > digmax) value = digmax;

            if (value < digmin) value = digmin;

            hdr->wrbuf[i * 3] = value & 0xff;

            hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;

            hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
        }

        if (fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
    }

    hdr->signal_write_sequence_pos++;

    if (hdr->signal_write_sequence_pos == hdr->edfsignals) {
        hdr->signal_write_sequence_pos = 0;

        if (edflib_write_tal(hdr, file)) return -1;

        hdr->datarecords++;

        fflush(file);
    }

    return 0;
}


int edf_blockwrite_digital_samples(int handle, int *buf) {
    int i, j,
            error,
            sf,
            digmax,
            digmin,
            edfsignals,
            buf_offset,
            value;

    FILE *file;

    struct edfhdrblock *hdr;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->edfsignals == 0) return -1;

    if (hdrlist[handle]->signal_write_sequence_pos) return -1;

    hdr = hdrlist[handle];

    file = hdr->file_hdl;

    edfsignals = hdr->edfsignals;

    if (!hdr->datarecords) {
        error = edflib_write_edf_header(hdr);

        if (error) return error;
    }

    buf_offset = 0;

    for (j = 0; j < edfsignals; j++) {
        sf = hdr->edfparam[j].smp_per_record;

        digmax = hdr->edfparam[j].dig_max;

        digmin = hdr->edfparam[j].dig_min;

        if (hdr->edf) {
            if (hdr->wrbufsize < (sf * 2)) {
                free(hdr->wrbuf);

                hdr->wrbufsize = 0;

                hdr->wrbuf = (char *) malloc(sf * 2);

                if (hdr->wrbuf == NULL) return -1;

                hdr->wrbufsize = sf * 2;
            }

            for (i = 0; i < sf; i++) {
                value = buf[i + buf_offset];

                if (value > digmax) value = digmax;

                if (value < digmin) value = digmin;

                hdr->wrbuf[i * 2] = value & 0xff;

                hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff;
            }

            if (fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1;
        } else  // BDF
        {
            if (hdr->wrbufsize < (sf * 3)) {
                free(hdr->wrbuf);

                hdr->wrbufsize = 0;

                hdr->wrbuf = (char *) malloc(sf * 3);

                if (hdr->wrbuf == NULL) return -1;

                hdr->wrbufsize = sf * 3;
            }

            for (i = 0; i < sf; i++) {
                value = buf[i + buf_offset];

                if (value > digmax) value = digmax;

                if (value < digmin) value = digmin;

                hdr->wrbuf[i * 3] = value & 0xff;

                hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;

                hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
            }

            if (fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
        }

        buf_offset += sf;
    }

    if (edflib_write_tal(hdr, file)) return -1;

    hdr->datarecords++;

    fflush(file);

    return 0;
}


int edf_blockwrite_digital_short_samples(int handle, short *buf) {
    int i, j,
            error,
            sf,
            digmax,
            digmin,
            edfsignals,
            buf_offset,
            value;

    FILE *file;

    struct edfhdrblock *hdr;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->edfsignals == 0) return -1;

    if (hdrlist[handle]->signal_write_sequence_pos) return -1;

    if (hdrlist[handle]->bdf == 1) return -1;

    hdr = hdrlist[handle];

    file = hdr->file_hdl;

    edfsignals = hdr->edfsignals;

    if (!hdr->datarecords) {
        error = edflib_write_edf_header(hdr);

        if (error) {
            return error;
        }
    }

    buf_offset = 0;

    for (j = 0; j < edfsignals; j++) {
        sf = hdr->edfparam[j].smp_per_record;

        digmax = hdr->edfparam[j].dig_max;

        digmin = hdr->edfparam[j].dig_min;

        if (hdr->edf) {
            if ((digmax != 0x7fff) || (digmin != -0x8000)) {
                for (i = 0; i < sf; i++) {
                    if (buf[i + buf_offset] > digmax) {
                        buf[i + buf_offset] = digmax;
                    }

                    if (buf[i + buf_offset] < digmin) {
                        buf[i + buf_offset] = digmin;
                    }
                }
            }

            if (fwrite(buf + buf_offset, sf * 2, 1, file) != 1) return -1;
        } else  // BDF
        {
            if (hdr->wrbufsize < (sf * 3)) {
                free(hdr->wrbuf);

                hdr->wrbufsize = 0;

                hdr->wrbuf = (char *) malloc(sf * 3);

                if (hdr->wrbuf == NULL) return -1;

                hdr->wrbufsize = sf * 3;
            }

            for (i = 0; i < sf; i++) {
                value = buf[i + buf_offset];

                if (value > digmax) value = digmax;

                if (value < digmin) value = digmin;

                hdr->wrbuf[i * 3] = value & 0xff;

                hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;

                hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
            }

            if (fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
        }

        buf_offset += sf;
    }

    if (edflib_write_tal(hdr, file)) return -1;

    hdr->datarecords++;

    fflush(file);

    return 0;
}


int edf_blockwrite_digital_3byte_samples(int handle, void *buf) {
    int j,
            error,
            edfsignals,
            total_samples = 0;

    FILE *file;

    struct edfhdrblock *hdr;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->edfsignals == 0) return -1;

    if (hdrlist[handle]->signal_write_sequence_pos) return -1;

    if (hdrlist[handle]->bdf != 1) return -1;

    hdr = hdrlist[handle];

    file = hdr->file_hdl;

    edfsignals = hdr->edfsignals;

    if (!hdr->datarecords) {
        error = edflib_write_edf_header(hdr);

        if (error) return error;
    }

    for (j = 0; j < edfsignals; j++) {
        total_samples += hdr->edfparam[j].smp_per_record;
    }

    if (fwrite(buf, total_samples * 3, 1, file) != 1) return -1;

    if (edflib_write_tal(hdr, file)) return -1;

    hdr->datarecords++;

    fflush(file);

    return 0;
}


int edfwrite_physical_samples(int handle, double *buf) {
    int i,
            error,
            sf,
            digmax,
            digmin,
            value,
            edfsignal;

    double bitvalue,
            phys_offset;

    FILE *file;

    struct edfhdrblock *hdr;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->edfsignals == 0) return -1;

    hdr = hdrlist[handle];

    file = hdr->file_hdl;

    edfsignal = hdr->signal_write_sequence_pos;

    if (!hdr->datarecords) {
        if (!edfsignal) {
            error = edflib_write_edf_header(hdr);

            if (error) return error;
        }
    }

    sf = hdr->edfparam[edfsignal].smp_per_record;

    digmax = hdr->edfparam[edfsignal].dig_max;

    digmin = hdr->edfparam[edfsignal].dig_min;

    bitvalue = hdr->edfparam[edfsignal].bitvalue;

    phys_offset = hdr->edfparam[edfsignal].offset;

    if (hdr->edf) {
        if (hdr->wrbufsize < (sf * 2)) {
            free(hdr->wrbuf);

            hdr->wrbufsize = 0;

            hdr->wrbuf = (char *) malloc(sf * 2);

            if (hdr->wrbuf == NULL) return -1;

            hdr->wrbufsize = sf * 2;
        }

        for (i = 0; i < sf; i++) {
            value = (buf[i] / bitvalue) - phys_offset;

            if (value > digmax) value = digmax;

            if (value < digmin) value = digmin;

            hdr->wrbuf[i * 2] = value & 0xff;

            hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff;
        }

        if (fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1;
    } else  // BDF
    {
        if (hdr->wrbufsize < (sf * 3)) {
            free(hdr->wrbuf);

            hdr->wrbufsize = 0;

            hdr->wrbuf = (char *) malloc(sf * 3);

            if (hdr->wrbuf == NULL) return -1;

            hdr->wrbufsize = sf * 3;
        }

        for (i = 0; i < sf; i++) {
            value = (buf[i] / bitvalue) - phys_offset;

            if (value > digmax) value = digmax;

            if (value < digmin) value = digmin;

            hdr->wrbuf[i * 3] = value & 0xff;

            hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;

            hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
        }

        if (fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
    }

    hdr->signal_write_sequence_pos++;

    if (hdr->signal_write_sequence_pos == hdr->edfsignals) {
        hdr->signal_write_sequence_pos = 0;

        if (edflib_write_tal(hdr, file)) return -1;

        hdr->datarecords++;

        fflush(file);
    }

    return 0;
}


int edf_blockwrite_physical_samples(int handle, double *buf) {
    int i, j,
            error,
            sf,
            digmax,
            digmin,
            edfsignals,
            buf_offset,
            value;

    double bitvalue,
            phys_offset;

    FILE *file;

    struct edfhdrblock *hdr;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->edfsignals == 0) return -1;

    if (hdrlist[handle]->signal_write_sequence_pos) return -1;

    hdr = hdrlist[handle];

    file = hdr->file_hdl;

    edfsignals = hdr->edfsignals;

    if (!hdr->datarecords) {
        error = edflib_write_edf_header(hdr);

        if (error) return error;
    }

    buf_offset = 0;

    for (j = 0; j < edfsignals; j++) {
        sf = hdr->edfparam[j].smp_per_record;

        digmax = hdr->edfparam[j].dig_max;

        digmin = hdr->edfparam[j].dig_min;

        bitvalue = hdr->edfparam[j].bitvalue;

        phys_offset = hdr->edfparam[j].offset;

        if (hdr->edf) {
            if (hdr->wrbufsize < (sf * 2)) {
                free(hdr->wrbuf);

                hdr->wrbufsize = 0;

                hdr->wrbuf = (char *) malloc(sf * 2);

                if (hdr->wrbuf == NULL) return -1;

                hdr->wrbufsize = sf * 2;
            }

            for (i = 0; i < sf; i++) {
                value = (buf[i + buf_offset] / bitvalue) - phys_offset;

                if (value > digmax) value = digmax;

                if (value < digmin) value = digmin;

                hdr->wrbuf[i * 2] = value & 0xff;

                hdr->wrbuf[i * 2 + 1] = (value >> 8) & 0xff;
            }

            if (fwrite(hdr->wrbuf, sf * 2, 1, file) != 1) return -1;
        } else  // BDF
        {
            if (hdr->wrbufsize < (sf * 3)) {
                free(hdr->wrbuf);

                hdr->wrbufsize = 0;

                hdr->wrbuf = (char *) malloc(sf * 3);

                if (hdr->wrbuf == NULL) return -1;

                hdr->wrbufsize = sf * 3;
            }

            for (i = 0; i < sf; i++) {
                value = (buf[i + buf_offset] / bitvalue) - phys_offset;

                if (value > digmax) value = digmax;

                if (value < digmin) value = digmin;

                hdr->wrbuf[i * 3] = value & 0xff;

                hdr->wrbuf[i * 3 + 1] = (value >> 8) & 0xff;

                hdr->wrbuf[i * 3 + 2] = (value >> 16) & 0xff;
            }

            if (fwrite(hdr->wrbuf, sf * 3, 1, file) != 1) return -1;
        }

        buf_offset += sf;
    }

    if (edflib_write_tal(hdr, file)) return -1;

    hdr->datarecords++;

    fflush(file);

    return 0;
}


static int edflib_write_edf_header(struct edfhdrblock *hdr) {
    int i, j, p, q,
            len,
            rest,
            edfsignals;

    char str[128];

    struct tm *date_time;

    time_t elapsed_time;

    FILE *file;

    file = hdr->file_hdl;

    edfsignals = hdr->edfsignals;

    if (edfsignals < 0) return EDFLIB_NO_SIGNALS;

    if (edfsignals > EDFLIB_MAXSIGNALS) return EDFLIB_TOO_MANY_SIGNALS;

    hdr->eq_sf = 1;

    hdr->recordsize = 0;

    hdr->total_annot_bytes = EDFLIB_ANNOTATION_BYTES * hdr->nr_annot_chns;

    for (i = 0; i < edfsignals; i++) {
        if (hdr->edfparam[i].smp_per_record < 1) return EDFLIB_NO_SAMPLES_IN_RECORD;

        if (hdr->edfparam[i].dig_max == hdr->edfparam[i].dig_min) return EDFLIB_DIGMIN_IS_DIGMAX;

        if (hdr->edfparam[i].dig_max < hdr->edfparam[i].dig_min)
            return EDFLIB_DIGMAX_LOWER_THAN_DIGMIN;

        if (hdr->edfparam[i].phys_max == hdr->edfparam[i].phys_min)
            return EDFLIB_PHYSMIN_IS_PHYSMAX;

        hdr->recordsize += hdr->edfparam[i].smp_per_record;

        if (i > 0) {
            if (hdr->edfparam[i].smp_per_record != hdr->edfparam[i - 1].smp_per_record) {
                hdr->eq_sf = 0;
            }
        }
    }

    if (hdr->edf) {
        hdr->recordsize *= 2;

        hdr->recordsize += hdr->total_annot_bytes;

        if (hdr->recordsize >
            (10 * 1024 * 1024))  /* datarecord size should not exceed 10MB for EDF */
        {
            return EDFLIB_DATARECORD_SIZE_TOO_BIG;
        }  /* if your application gets hit by this limitation, lower the value for the datarecord duration */
        /* using the function edf_set_datarecord_duration() */
    } else {
        hdr->recordsize *= 3;

        hdr->recordsize += hdr->total_annot_bytes;

        if (hdr->recordsize >
            (15 * 1024 * 1024))  /* datarecord size should not exceed 15MB for BDF */
        {
            return EDFLIB_DATARECORD_SIZE_TOO_BIG;
        }  /* if your application gets hit by this limitation, lower the value for the datarecord duration */
        /* using the function edf_set_datarecord_duration() */
    }

    for (i = 0; i < edfsignals; i++) {
        hdr->edfparam[i].bitvalue = (hdr->edfparam[i].phys_max - hdr->edfparam[i].phys_min) /
                                    (hdr->edfparam[i].dig_max - hdr->edfparam[i].dig_min);
        hdr->edfparam[i].offset =
                hdr->edfparam[i].phys_max / hdr->edfparam[i].bitvalue - hdr->edfparam[i].dig_max;
    }

    rewind(file);

    if (hdr->edf) {
        fprintf(file, "0       ");
    } else {
        fputc(255, file);
        fprintf(file, "BIOSEMI");
    }

    p = 0;

    if (hdr->plus_birthdate[0] == 0) {
        rest = 72;
    } else {
        rest = 62;
    }

    len = strlen(hdr->plus_patientcode);
    if (len && rest) {
        if (len > rest) {
            len = rest;
            rest = 0;
        } else {
            rest -= len;
        }
        edflib_strlcpy(str, hdr->plus_patientcode, 128);
        edflib_latin1_to_ascii(str, len);
        str[len] = 0;
        for (i = 0; i < len; i++) {
            if (str[i] == ' ') {
                str[i] = '_';
            }
        }
        p += fprintf(file, "%s ", str);
    } else {
        p += fprintf(file, "X ");
    }

    if (hdr->plus_gender[0] == 'M') {
        fputc('M', file);
    } else {
        if (hdr->plus_gender[0] == 'F') {
            fputc('F', file);
        } else {
            fputc('X', file);
        }
    }
    fputc(' ', file);
    p += 2;

    if (hdr->plus_birthdate[0] == 0) {
        fputc('X', file);
        fputc(' ', file);

        p += 2;
    } else {
        fputc(hdr->plus_birthdate[0], file);
        fputc(hdr->plus_birthdate[1], file);
        fputc('-', file);
        q = edflib_atoi_nonlocalized(&(hdr->plus_birthdate[3]));
        switch (q) {
            case 1:
                fprintf(file, "JAN");
                break;
            case 2:
                fprintf(file, "FEB");
                break;
            case 3:
                fprintf(file, "MAR");
                break;
            case 4:
                fprintf(file, "APR");
                break;
            case 5:
                fprintf(file, "MAY");
                break;
            case 6:
                fprintf(file, "JUN");
                break;
            case 7:
                fprintf(file, "JUL");
                break;
            case 8:
                fprintf(file, "AUG");
                break;
            case 9:
                fprintf(file, "SEP");
                break;
            case 10:
                fprintf(file, "OCT");
                break;
            case 11:
                fprintf(file, "NOV");
                break;
            case 12:
                fprintf(file, "DEC");
                break;
        }
        fputc('-', file);
        fputc(hdr->plus_birthdate[6], file);
        fputc(hdr->plus_birthdate[7], file);
        fputc(hdr->plus_birthdate[8], file);
        fputc(hdr->plus_birthdate[9], file);
        fputc(' ', file);

        p += 12;
    }

    len = strlen(hdr->plus_patient_name);
    if (len && rest) {
        if (len > rest) {
            len = rest;
            rest = 0;
        } else {
            rest -= len;
        }
        edflib_strlcpy(str, hdr->plus_patient_name, 128);
        edflib_latin1_to_ascii(str, len);
        str[len] = 0;
        for (i = 0; i < len; i++) {
            if (str[i] == ' ') {
                str[i] = '_';
            }
        }
        p += fprintf(file, "%s", str);
    } else {
        fputc('X', file);

        p++;
    }

    if (rest) {
        fputc(' ', file);

        p++;

        rest--;
    }

    len = strlen(hdr->plus_patient_additional);
    if (len && rest) {
        if (len > rest) {
            len = rest;
        }
        edflib_strlcpy(str, hdr->plus_patient_additional, 128);
        edflib_latin1_to_ascii(str, len);
        str[len] = 0;
        p += fprintf(file, "%s", str);
    }

    for (; p < 80; p++) {
        fputc(' ', file);
    }

    if (!hdr->startdate_year) {
        elapsed_time = time(NULL);
        date_time = localtime(&elapsed_time);

        hdr->startdate_year = date_time->tm_year + 1900;
        hdr->startdate_month = date_time->tm_mon + 1;
        hdr->startdate_day = date_time->tm_mday;
        hdr->starttime_hour = date_time->tm_hour;
        hdr->starttime_minute = date_time->tm_min;
        hdr->starttime_second = date_time->tm_sec % 60;
    }

    p = 0;

    p += fprintf(file, "Startdate %02u-", hdr->startdate_day);
    switch (hdr->startdate_month) {
        case 1 :
            fprintf(file, "JAN");
            break;
        case 2 :
            fprintf(file, "FEB");
            break;
        case 3 :
            fprintf(file, "MAR");
            break;
        case 4 :
            fprintf(file, "APR");
            break;
        case 5 :
            fprintf(file, "MAY");
            break;
        case 6 :
            fprintf(file, "JUN");
            break;
        case 7 :
            fprintf(file, "JUL");
            break;
        case 8 :
            fprintf(file, "AUG");
            break;
        case 9 :
            fprintf(file, "SEP");
            break;
        case 10 :
            fprintf(file, "OCT");
            break;
        case 11 :
            fprintf(file, "NOV");
            break;
        case 12 :
            fprintf(file, "DEC");
            break;
    }
    p += 3;
    fputc('-', file);
    p++;
    p += edflib_fprint_int_number_nonlocalized(file, hdr->startdate_year, 4, 0);
    fputc(' ', file);
    p++;

    rest = 42;

    len = strlen(hdr->plus_admincode);
    if (len && rest) {
        if (len > rest) {
            len = rest;
            rest = 0;
        } else {
            rest -= len;
        }
        edflib_strlcpy(str, hdr->plus_admincode, 128);
        edflib_latin1_to_ascii(str, len);
        str[len] = 0;
        for (i = 0; i < len; i++) {
            if (str[i] == ' ') {
                str[i] = '_';
            }
        }
        p += fprintf(file, "%s", str);
    } else {
        p += fprintf(file, "X");
    }

    if (rest) {
        fputc(' ', file);

        p++;

        rest--;
    }

    len = strlen(hdr->plus_technician);
    if (len && rest) {
        if (len > rest) {
            len = rest;
            rest = 0;
        } else {
            rest -= len;
        }
        edflib_strlcpy(str, hdr->plus_technician, 128);
        edflib_latin1_to_ascii(str, len);
        str[len] = 0;
        for (i = 0; i < len; i++) {
            if (str[i] == ' ') {
                str[i] = '_';
            }
        }
        p += fprintf(file, "%s", str);
    } else {
        p += fprintf(file, "X");
    }

    if (rest) {
        fputc(' ', file);

        p++;

        rest--;
    }

    len = strlen(hdr->plus_equipment);
    if (len && rest) {
        if (len > rest) {
            len = rest;
            rest = 0;
        } else {
            rest -= len;
        }
        edflib_strlcpy(str, hdr->plus_equipment, 128);
        edflib_latin1_to_ascii(str, len);
        str[len] = 0;
        for (i = 0; i < len; i++) {
            if (str[i] == ' ') {
                str[i] = '_';
            }
        }
        p += fprintf(file, "%s", str);
    } else {
        p += fprintf(file, "X");
    }

    if (rest) {
        fputc(' ', file);

        p++;

        rest--;
    }

    len = strlen(hdr->plus_recording_additional);
    if (len && rest) {
        if (len > rest) {
            len = rest;
        }
        edflib_strlcpy(str, hdr->plus_recording_additional, 128);
        edflib_latin1_to_ascii(str, len);
        str[len] = 0;
        p += fprintf(file, "%s", str);
    }

    for (; p < 80; p++) {
        fputc(' ', file);
    }

    fprintf(file, "%02u.%02u.%02u", hdr->startdate_day, hdr->startdate_month,
            (hdr->startdate_year % 100));
    fprintf(file, "%02u.%02u.%02u", hdr->starttime_hour, hdr->starttime_minute,
            hdr->starttime_second);
    p = edflib_fprint_int_number_nonlocalized(file, (edfsignals + hdr->nr_annot_chns + 1) * 256, 0,
                                              0);
    for (; p < 8; p++) {
        fputc(' ', file);
    }
    if (hdr->edf) {
        fprintf(file, "EDF+C");
    } else {
        fprintf(file, "BDF+C");
    }
    for (i = 0; i < 39; i++) {
        fputc(' ', file);
    }
    fprintf(file, "-1      ");
    if (hdr->long_data_record_duration == EDFLIB_TIME_DIMENSION) {
        fprintf(file, "1       ");
    } else {
        edflib_snprint_number_nonlocalized(str, hdr->data_record_duration, 128);
        edflib_strlcat(str, "        ", 128);
        str[8] = 0;
        fprintf(file, "%s", str);
    }
    p = edflib_fprint_int_number_nonlocalized(file, edfsignals + hdr->nr_annot_chns, 0, 0);
    for (; p < 4; p++) {
        fputc(' ', file);
    }

    for (i = 0; i < edfsignals; i++) {
        len = strlen(hdr->edfparam[i].label);
        edflib_latin1_to_ascii(hdr->edfparam[i].label, len);
        for (j = 0; j < len; j++) {
            fputc(hdr->edfparam[i].label[j], file);
        }
        for (; j < 16; j++) {
            fputc(' ', file);
        }
    }
    for (j = 0; j < hdr->nr_annot_chns; j++) {
        if (hdr->edf) {
            fprintf(file, "EDF Annotations ");
        } else {
            fprintf(file, "BDF Annotations ");
        }
    }
    for (i = 0; i < edfsignals; i++) {
        len = strlen(hdr->edfparam[i].transducer);
        edflib_latin1_to_ascii(hdr->edfparam[i].transducer, len);
        for (j = 0; j < len; j++) {
            fputc(hdr->edfparam[i].transducer[j], file);
        }
        for (; j < 80; j++) {
            fputc(' ', file);
        }
    }
    for (j = 0; j < hdr->nr_annot_chns; j++) {
        for (i = 0; i < 80; i++) {
            fputc(' ', file);
        }
    }
    for (i = 0; i < edfsignals; i++) {
        len = strlen(hdr->edfparam[i].physdimension);
        edflib_latin1_to_ascii(hdr->edfparam[i].physdimension, len);
        for (j = 0; j < len; j++) {
            fputc(hdr->edfparam[i].physdimension[j], file);
        }
        for (; j < 8; j++) {
            fputc(' ', file);
        }
    }
    for (j = 0; j < hdr->nr_annot_chns; j++) {
        fprintf(file, "        ");
    }
    for (i = 0; i < edfsignals; i++) {
        p = edflib_snprint_number_nonlocalized(str, hdr->edfparam[i].phys_min, 128);
        for (; p < 8; p++) {
            str[p] = ' ';
        }
        str[8] = 0;
        fprintf(file, "%s", str);
    }
    for (j = 0; j < hdr->nr_annot_chns; j++) {
        fprintf(file, "-1      ");
    }
    for (i = 0; i < edfsignals; i++) {
        p = edflib_snprint_number_nonlocalized(str, hdr->edfparam[i].phys_max, 128);
        for (; p < 8; p++) {
            str[p] = ' ';
        }
        str[8] = 0;
        fprintf(file, "%s", str);
    }
    for (j = 0; j < hdr->nr_annot_chns; j++) {
        fprintf(file, "1       ");
    }
    for (i = 0; i < edfsignals; i++) {
        p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].dig_min, 0, 0);
        for (; p < 8; p++) {
            fputc(' ', file);
        }
    }
    for (j = 0; j < hdr->nr_annot_chns; j++) {
        if (hdr->edf) {
            fprintf(file, "-32768  ");
        } else {
            fprintf(file, "-8388608");
        }
    }
    for (i = 0; i < edfsignals; i++) {
        p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].dig_max, 0, 0);
        for (; p < 8; p++) {
            fputc(' ', file);
        }
    }
    for (j = 0; j < hdr->nr_annot_chns; j++) {
        if (hdr->edf) {
            fprintf(file, "32767   ");
        } else {
            fprintf(file, "8388607 ");
        }
    }
    for (i = 0; i < edfsignals; i++) {
        len = strlen(hdr->edfparam[i].prefilter);
        edflib_latin1_to_ascii(hdr->edfparam[i].prefilter, len);
        for (j = 0; j < len; j++) {
            fputc(hdr->edfparam[i].prefilter[j], file);
        }
        for (; j < 80; j++) {
            fputc(' ', file);
        }
    }
    for (i = 0; i < hdr->nr_annot_chns; i++) {
        for (j = 0; j < 80; j++) {
            fputc(' ', file);
        }
    }
    for (i = 0; i < edfsignals; i++) {
        p = edflib_fprint_int_number_nonlocalized(file, hdr->edfparam[i].smp_per_record, 0, 0);
        for (; p < 8; p++) {
            fputc(' ', file);
        }
    }
    for (j = 0; j < hdr->nr_annot_chns; j++) {
        if (hdr->edf) {
            p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 2, 0, 0);
            for (; p < 8; p++) {
                fputc(' ', file);
            }
        } else {
            p = edflib_fprint_int_number_nonlocalized(file, EDFLIB_ANNOTATION_BYTES / 3, 0, 0);
            for (; p < 8; p++) {
                fputc(' ', file);
            }
        }
    }
    for (i = 0; i < (edfsignals * 32); i++) {
        fputc(' ', file);
    }
    for (i = 0; i < (hdr->nr_annot_chns * 32); i++) {
        fputc(' ', file);
    }

    return 0;
}


int edf_set_label(int handle, int edfsignal, const char *label) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((edfsignal < 0) || (edfsignal >= hdrlist[handle]->edfsignals)) return -1;

    strncpy(hdrlist[handle]->edfparam[edfsignal].label, label, 16);

    hdrlist[handle]->edfparam[edfsignal].label[16] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->edfparam[edfsignal].label);

    return 0;
}


int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((edfsignal < 0) || (edfsignal >= hdrlist[handle]->edfsignals)) return -1;

    strncpy(hdrlist[handle]->edfparam[edfsignal].physdimension, phys_dim, 8);

    hdrlist[handle]->edfparam[edfsignal].physdimension[8] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->edfparam[edfsignal].physdimension);

    return 0;
}


int edf_set_physical_maximum(int handle, int edfsignal, double phys_max) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((edfsignal < 0) || (edfsignal >= hdrlist[handle]->edfsignals)) return -1;

    hdrlist[handle]->edfparam[edfsignal].phys_max = phys_max;

    return 0;
}


int edf_set_physical_minimum(int handle, int edfsignal, double phys_min) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((edfsignal < 0) || (edfsignal >= hdrlist[handle]->edfsignals)) return -1;

    hdrlist[handle]->edfparam[edfsignal].phys_min = phys_min;

    return 0;
}


int edf_set_digital_maximum(int handle, int edfsignal, int dig_max) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((edfsignal < 0) || (edfsignal >= hdrlist[handle]->edfsignals)) return -1;

    if (hdrlist[handle]->edf) {
        if (dig_max > 0x7fff) return -1;
    } else {
        if (dig_max > 0x7fffff) return -1;
    }

    hdrlist[handle]->edfparam[edfsignal].dig_max = dig_max;

    return 0;
}


int edf_set_digital_minimum(int handle, int edfsignal, int dig_min) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((edfsignal < 0) || (edfsignal >= hdrlist[handle]->edfsignals)) return -1;

    if (hdrlist[handle]->edf) {
        if (dig_min < (-0x8000)) return -1;
    } else {
        if (dig_min < (-0x800000)) return -1;
    }

    hdrlist[handle]->edfparam[edfsignal].dig_min = dig_min;

    return 0;
}


int edf_set_patientname(int handle, const char *patientname) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->plus_patient_name, patientname, 80);

    hdrlist[handle]->plus_patient_name[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_patient_name);

    return 0;
}


int edf_set_patientcode(int handle, const char *patientcode) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->plus_patientcode, patientcode, 80);

    hdrlist[handle]->plus_patientcode[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_patientcode);

    return 0;
}


int edf_set_gender(int handle, int gender) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((gender < 0) || (gender > 1)) return -1;

    if (gender) {
        hdrlist[handle]->plus_gender[0] = 'M';
    } else {
        hdrlist[handle]->plus_gender[0] = 'F';
    }

    hdrlist[handle]->plus_gender[1] = 0;

    return 0;
}


int edf_set_birthdate(int handle, int birthdate_year, int birthdate_month, int birthdate_day) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((birthdate_year < 1800) || (birthdate_year > 3000) ||
        (birthdate_month < 1) || (birthdate_month > 12) ||
        (birthdate_day < 1) || (birthdate_day > 31)) {
        return -1;
    }

    sprintf(hdrlist[handle]->plus_birthdate, "%02i.%02i.%02i%02i", birthdate_day, birthdate_month,
            birthdate_year / 100, birthdate_year % 100);

    hdrlist[handle]->plus_birthdate[10] = 0;

    return 0;
}


int edf_set_patient_additional(int handle, const char *patient_additional) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->plus_patient_additional, patient_additional, 80);

    hdrlist[handle]->plus_patient_additional[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_patient_additional);

    return 0;
}


int edf_set_admincode(int handle, const char *admincode) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->plus_admincode, admincode, 80);

    hdrlist[handle]->plus_admincode[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_admincode);

    return 0;
}


int edf_set_technician(int handle, const char *technician) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->plus_technician, technician, 80);

    hdrlist[handle]->plus_technician[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_technician);

    return 0;
}


int edf_set_equipment(int handle, const char *equipment) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->plus_equipment, equipment, 80);

    hdrlist[handle]->plus_equipment[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_equipment);

    return 0;
}


int edf_set_recording_additional(int handle, const char *recording_additional) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->plus_recording_additional, recording_additional, 80);

    hdrlist[handle]->plus_recording_additional[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->plus_recording_additional);

    return 0;
}


int edf_set_startdatetime(int handle, int startdate_year, int startdate_month, int startdate_day,
                          int starttime_hour, int starttime_minute, int starttime_second) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((startdate_year < 1985) || (startdate_year > 2084) ||
        (startdate_month < 1) || (startdate_month > 12) ||
        (startdate_day < 1) || (startdate_day > 31) ||
        (starttime_hour < 0) || (starttime_hour > 23) ||
        (starttime_minute < 0) || (starttime_minute > 59) ||
        (starttime_second < 0) || (starttime_second > 59)) {
        return -1;
    }

    hdrlist[handle]->startdate_year = startdate_year;
    hdrlist[handle]->startdate_month = startdate_month;
    hdrlist[handle]->startdate_day = startdate_day;
    hdrlist[handle]->starttime_hour = starttime_hour;
    hdrlist[handle]->starttime_minute = starttime_minute;
    hdrlist[handle]->starttime_second = starttime_second;

    return 0;
}


int
edfwrite_annotation_utf8(int handle, long long onset, long long duration, const char *description) {
    int i;

    struct edf_write_annotationblock *list_annot, *malloc_list;

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (onset < 0LL) return -1;

    if (hdrlist[handle]->annots_in_file >= hdrlist[handle]->annotlist_sz) {
        malloc_list = (struct edf_write_annotationblock *) realloc(write_annotationslist[handle],
                                                                   sizeof(struct edf_write_annotationblock) *
                                                                   (hdrlist[handle]->annotlist_sz +
                                                                    EDFLIB_ANNOT_MEMBLOCKSZ));
        if (malloc_list == NULL) {
            return -1;
        }

        write_annotationslist[handle] = malloc_list;

        hdrlist[handle]->annotlist_sz += EDFLIB_ANNOT_MEMBLOCKSZ;
    }

    list_annot = write_annotationslist[handle] + hdrlist[handle]->annots_in_file;

    list_annot->onset = onset;
    list_annot->duration = duration;
    strncpy(list_annot->annotation, description, EDFLIB_WRITE_MAX_ANNOTATION_LEN);
    list_annot->annotation[EDFLIB_WRITE_MAX_ANNOTATION_LEN] = 0;

    for (i = 0;; i++) {
        if (list_annot->annotation[i] == 0) {
            break;
        }

        if (((unsigned char *) (list_annot->annotation))[i] < 32) {
            list_annot->annotation[i] = '.';
        }
    }

    hdrlist[handle]->annots_in_file++;

    return 0;
}


int edfwrite_annotation_latin1(int handle, long long onset, long long duration,
                               const char *description) {
    struct edf_write_annotationblock *list_annot, *malloc_list;

    char str[EDFLIB_WRITE_MAX_ANNOTATION_LEN + 1];

    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (onset < 0LL) return -1;

    if (hdrlist[handle]->annots_in_file >= hdrlist[handle]->annotlist_sz) {
        malloc_list = (struct edf_write_annotationblock *) realloc(write_annotationslist[handle],
                                                                   sizeof(struct edf_write_annotationblock) *
                                                                   (hdrlist[handle]->annotlist_sz +
                                                                    EDFLIB_ANNOT_MEMBLOCKSZ));
        if (malloc_list == NULL) {
            return -1;
        }

        write_annotationslist[handle] = malloc_list;

        hdrlist[handle]->annotlist_sz += EDFLIB_ANNOT_MEMBLOCKSZ;
    }

    list_annot = write_annotationslist[handle] + hdrlist[handle]->annots_in_file;

    list_annot->onset = onset;
    list_annot->duration = duration;
    strncpy(str, description, EDFLIB_WRITE_MAX_ANNOTATION_LEN);
    str[EDFLIB_WRITE_MAX_ANNOTATION_LEN] = 0;
    edflib_latin12utf8(str, strlen(str));
    strncpy(list_annot->annotation, str, EDFLIB_WRITE_MAX_ANNOTATION_LEN);
    list_annot->annotation[EDFLIB_WRITE_MAX_ANNOTATION_LEN] = 0;

    hdrlist[handle]->annots_in_file++;

    return 0;
}


static void edflib_remove_padding_trailing_spaces(char *str) {
    int i;

    while (str[0] == ' ') {
        for (i = 0;; i++) {
            if (str[i] == 0) {
                break;
            }

            str[i] = str[i + 1];
        }
    }

    for (i = strlen(str); i > 0; i--) {
        if (str[i - 1] == ' ') {
            str[i - 1] = 0;
        } else {
            break;
        }
    }
}


int edf_set_prefilter(int handle, int edfsignal, const char *prefilter) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((edfsignal < 0) || (edfsignal >= hdrlist[handle]->edfsignals)) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->edfparam[edfsignal].prefilter, prefilter, 80);

    hdrlist[handle]->edfparam[edfsignal].prefilter[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->edfparam[edfsignal].prefilter);

    return 0;
}


int edf_set_transducer(int handle, int edfsignal, const char *transducer) {
    if ((handle < 0) || (handle >= EDFLIB_MAXFILES)) return -1;

    if (hdrlist[handle] == NULL) return -1;

    if (!hdrlist[handle]->writemode) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    if ((edfsignal < 0) || (edfsignal >= hdrlist[handle]->edfsignals)) return -1;

    if (hdrlist[handle]->datarecords) return -1;

    strncpy(hdrlist[handle]->edfparam[edfsignal].transducer, transducer, 80);

    hdrlist[handle]->edfparam[edfsignal].transducer[80] = 0;

    edflib_remove_padding_trailing_spaces(hdrlist[handle]->edfparam[edfsignal].transducer);

    return 0;
}


/* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */
/* if sign is zero, only negative numbers will have the sign '-' character */
/* if sign is one, the sign '+' or '-' character will always be printed */
/* returns the amount of characters printed */
static int edflib_fprint_int_number_nonlocalized(FILE *file, int q, int minimum, int sign) {
    int flag = 0, z, i, j = 0, base = 1000000000;

    if (minimum < 0) {
        minimum = 0;
    }

    if (minimum > 9) {
        flag = 1;
    }

    if (q < 0) {
        fputc('-', file);

        j++;

        base = -base;
    } else {
        if (sign) {
            fputc('+', file);

            j++;
        }
    }

    for (i = 10; i; i--) {
        if (minimum == i) {
            flag = 1;
        }

        z = q / base;

        q %= base;

        if (z || flag) {
            fputc('0' + z, file);

            j++;

            flag = 1;
        }

        base /= 10;
    }

    if (!flag) {
        fputc('0', file);

        j++;
    }

    return j;
}


/* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */
/* if sign is zero, only negative numbers will have the sign '-' character */
/* if sign is one, the sign '+' or '-' character will always be printed */
/* returns the amount of characters printed */
static int edflib_fprint_ll_number_nonlocalized(FILE *file, long long q, int minimum, int sign) {
    int flag = 0, z, i, j = 0;

    long long base = 1000000000000000000LL;

    if (minimum < 0) {
        minimum = 0;
    }

    if (minimum > 18) {
        flag = 1;
    }

    if (q < 0LL) {
        fputc('-', file);

        j++;

        base = -base;
    } else {
        if (sign) {
            fputc('+', file);

            j++;
        }
    }

    for (i = 19; i; i--) {
        if (minimum == i) {
            flag = 1;
        }

        z = q / base;

        q %= base;

        if (z || flag) {
            fputc('0' + z, file);

            j++;

            flag = 1;
        }

        base /= 10LL;
    }

    if (!flag) {
        fputc('0', file);

        j++;
    }

    return j;
}


/* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */
/* if sign is zero, only negative numbers will have the sign '-' character */
/* if sign is one, the sign '+' or '-' character will always be printed */
/* returns the amount of characters printed */
/*
static int edflib_sprint_int_number_nonlocalized(char *str, int q, int minimum, int sign)
{
  int flag=0, z, i, j=0, base = 1000000000;

  if(minimum < 0)
  {
    minimum = 0;
  }

  if(minimum > 9)
  {
    flag = 1;
  }

  if(q < 0)
  {
    str[j++] = '-';

    q = -q;
  }
  else
  {
    if(sign)
    {
      str[j++] = '+';
    }
  }

  for(i=10; i; i--)
  {
    if(minimum == i)
    {
      flag = 1;
    }

    z = q / base;

    q %= base;

    if(z || flag)
    {
      str[j++] = '0' + z;

      flag = 1;
    }

    base /= 10;
  }

  if(!flag)
  {
    str[j++] = '0';
  }

  str[j] = 0;

  return j;
}
*/

/* minimum is the minimum digits that will be printed (minus sign not included), leading zero's will be added if necessary */
/* if sign is zero, only negative numbers will have the sign '-' character */
/* if sign is one, the sign '+' or '-' character will always be printed */
/* returns the amount of characters printed */
static int
edflib_snprint_ll_number_nonlocalized(char *dest, long long q, int minimum, int sign, int sz) {
    int flag = 0, z, i, j = 0;

    long long base = 1000000000000000000LL;

    if (sz < 1) {
        return 0;
    }

    if (minimum < 0) {
        minimum = 0;
    }

    if (minimum > 18) {
        flag = 1;
    }

    if (q < 0LL) {
        dest[j++] = '-';

        base = -base;
    } else {
        if (sign) {
            dest[j++] = '+';
        }
    }

    if (j == sz) {
        dest[--j] = 0;

        return j;
    }

    for (i = 19; i; i--) {
        if (minimum == i) {
            flag = 1;
        }

        z = q / base;

        q %= base;

        if (z || flag) {
            dest[j++] = '0' + z;

            if (j == sz) {
                dest[--j] = 0;

                return j;
            }

            flag = 1;
        }

        base /= 10LL;
    }

    if (!flag) {
        dest[j++] = '0';
    }

    if (j == sz) {
        dest[--j] = 0;

        return j;
    }

    dest[j] = 0;

    return j;
}


static int edflib_snprint_number_nonlocalized(char *dest, double val, int sz) {
    int flag = 0, z, i, j = 0, q, base = 1000000000;

    double var;

    if (sz < 1) return 0;

    q = (int) val;

    var = val - q;

    if (val < 0.0) {
        dest[j++] = '-';

        if (q < 0) {
            base = -base;
        }
    }

    if (j == sz) {
        dest[--j] = 0;

        return j;
    }

    for (i = 10; i; i--) {
        z = q / base;

        q %= base;

        if (z || flag) {
            dest[j++] = '0' + z;

            if (j == sz) {
                dest[--j] = 0;

                return j;
            }

            flag = 1;
        }

        base /= 10;
    }

    if (!flag) {
        dest[j++] = '0';
    }

    if (j == sz) {
        dest[--j] = 0;

        return j;
    }

    base = 100000000;

    var *= (base * 10);

    q = (int) var;

    if (q < 0) {
        base = -base;
    }

    if (!q) {
        dest[j] = 0;

        return j;
    }

    dest[j++] = '.';

    if (j == sz) {
        dest[--j] = 0;

        return j;
    }

    for (i = 9; i; i--) {
        z = q / base;

        q %= base;

        dest[j++] = '0' + z;

        if (j == sz) {
            dest[--j] = 0;

            return j;
        }

        base /= 10;
    }

    dest[j] = 0;

    j--;

    for (; j > 0; j--) {
        if (dest[j] == '0') {
            dest[j] = 0;
        } else {
            j++;

            break;
        }
    }

    return j;
}


static double edflib_atof_nonlocalized(const char *str) {
    int i = 0, j, dot_pos = -1, decimals = 0, sign = 1, exp_pos = -1, exp_sign = 1, exp_val = 0;

    double value, value2 = 0.0;


    value = edflib_atoi_nonlocalized(str);

    while (str[i] == ' ') {
        i++;
    }

    if ((str[i] == '+') || (str[i] == '-')) {
        if (str[i] == '-') {
            sign = -1;
        }

        i++;
    }

    for (;; i++) {
        if (str[i] == 0) {
            break;
        }

        if ((str[i] == 'e') || (str[i] == 'E')) {
            exp_pos = i;

            break;
        }

        if (((str[i] < '0') || (str[i] > '9')) && (str[i] != '.')) {
            break;
        }

        if (dot_pos >= 0) {
            if ((str[i] >= '0') && (str[i] <= '9')) {
                decimals++;
            } else {
                break;
            }
        }

        if (str[i] == '.') {
            if (dot_pos < 0) {
                dot_pos = i;
            }
        }
    }

    if (decimals) {
        value2 = edflib_atoi_nonlocalized(str + dot_pos + 1) * sign;

        i = 1;

        while (decimals--) {
            i *= 10;
        }

        value2 /= i;

        value += value2;
    }

    if (exp_pos > 0) {
        i = exp_pos + 1;

        if (str[i]) {
            if (str[i] == '+') {
                i++;
            } else if (str[i] == '-') {
                exp_sign = -1;

                i++;
            }

            if (str[i]) {
                exp_val = edflib_atoi_nonlocalized(str + i);

                if (exp_val > 0) {
                    for (j = 0; j < exp_val; j++) {
                        if (exp_sign > 0) {
                            value *= 10;
                        } else {
                            value /= 10;
                        }
                    }
                }
            }
        }
    }

    return value;
}


static int edflib_atoi_nonlocalized(const char *str) {
    int i = 0, value = 0, sign = 1;

    while (str[i] == ' ') {
        i++;
    }

    if ((str[i] == '+') || (str[i] == '-')) {
        if (str[i] == '-') {
            sign = -1;
        }

        i++;
    }

    for (;; i++) {
        if (str[i] == 0) {
            break;
        }

        if ((str[i] < '0') || (str[i] > '9')) {
            break;
        }

        value *= 10;

        value += ((str[i] - '0') * sign);
    }

    return value;
}


static int edflib_write_tal(struct edfhdrblock *hdr, FILE *file) {
    int p;

    char str[EDFLIB_ANNOTATION_BYTES * (EDFLIB_MAX_ANNOTATION_CHANNELS + 1)];

    p = edflib_snprint_ll_number_nonlocalized(str,
                                              (hdr->datarecords * hdr->long_data_record_duration +
                                               hdr->starttime_offset) / EDFLIB_TIME_DIMENSION, 0, 1,
                                              EDFLIB_ANNOTATION_BYTES *
                                              (EDFLIB_MAX_ANNOTATION_CHANNELS + 1));
    if ((hdr->long_data_record_duration % EDFLIB_TIME_DIMENSION) || (hdr->starttime_offset)) {
        str[p++] = '.';
        p += edflib_snprint_ll_number_nonlocalized(str + p, (hdr->datarecords *
                                                             hdr->long_data_record_duration +
                                                             hdr->starttime_offset) %
                                                            EDFLIB_TIME_DIMENSION, 7, 0,
                                                   (EDFLIB_ANNOTATION_BYTES *
                                                    (EDFLIB_MAX_ANNOTATION_CHANNELS + 1)) - p);
    }
    str[p++] = 20;
    str[p++] = 20;
    for (; p < hdr->total_annot_bytes; p++) {
        str[p] = 0;
    }

    if (fwrite(str, hdr->total_annot_bytes, 1, file) != 1) {
        return -1;
    }

    return 0;
}


static int edflib_strlcpy(char *dst, const char *src, int sz) {
    int srclen;

    sz--;

    srclen = strlen(src);

    if (srclen > sz) srclen = sz;

    memcpy(dst, src, srclen);

    dst[srclen] = 0;

    return srclen;
}


static int edflib_strlcat(char *dst, const char *src, int sz) {
    int srclen,
            dstlen;

    dstlen = strlen(dst);

    sz -= dstlen + 1;

    if (!sz) return dstlen;

    srclen = strlen(src);

    if (srclen > sz) srclen = sz;

    memcpy(dst + dstlen, src, srclen);

    dst[dstlen + srclen] = 0;

    return (dstlen + srclen);
}



























